整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

Vue3 学习笔记,如何使用 watch 监听数据变

Vue3 学习笔记,如何使用 watch 监听数据变化(五)

家好,本篇文章我们继续学习和 Vue 相关的内容,今天我们归纳总结下如何使用 watch 监听组件中的数据变化,以及 computed 和 watch 的区别。

什么是 watch,以及如何使用?

watch 是 Vue.js 中用于监听数据变化的一种机制。它允许我们在数据发生变化时执行特定的操作。

在 Vue 中使用 watch 的方法如下:

1.在 Vue 组件中,定义一个 watch 对象,其中包含要监听的数据属性以及对应的回调函数。

watch: {
  dataName: function(newValue, oldValue) {
    // code
  }
}

其中,dataName 是要监听的数据名称,newValue 是新的值,oldValue 是旧的值。

2.在 Vue 实例中,使用 $watch() 方法进行监听

vm.$watch('someData', function(newVal, oldVal) {
  // do something with newVal
});

注意:watch 回调函数会在侦听的数据发生变化时立即执行,而 computed 属性只有在其依赖的数据发生变化时才会计算。

watch 通常用于监听一个数据的变化并执行复杂的业务逻辑,例如在某个数据变化后需要进行 HTTP 请求或者调用其他函数。

下面是一个简单的 watch 的例子:

<template>
  <div>
    <input v-model="message" type="text" placeholder="请输入内容">
    <p>{{ message }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: '',
    }
  },
  watch: {
    message: function (newVal, oldVal) {
      console.log('message changed from ' + oldVal + ' to ' + newVal)
    }
  },
}
</script>

在这个例子中,我们使用了 watch 来监听 message 的变化,并在数据变化时打印出更改前后的值。

当然,watch 还可以接收一个对象,其中可以定义多个监听器。这里有一个例子,它监听了多个数据:

watch: {
  firstName: function (newVal, oldVal) {
    console.log('firstName changed from ' + oldVal + ' to ' + newVal)
  },
  lastName: function (newVal, oldVal) {
    console.log('lastName changed from ' + oldVal + ' to ' + newVal)
  }
}

一些高级用法介绍

1、深度观察 (deep: true):如果你希望对对象内部属性的变化进行监听,可以使用 deep: true 选项。

data() {
  user: {
    name: 'John',
    age: 25
  }
},
watch: {
  'user.name': function (val) {
    console.log('user name changed:', val)
  }
}

在这个例子中,我们监听了 user 对象中的 name 属性,当该属性变化时,会执行回调函数。

2、设置初始值 (immediate: true):如果你希望 watch 在组件创建时立即执行一次,可以使用 immediate: true 选项。

data() {
    count: 0
},
watch: {
    count: {
        handler: function (val, oldVal) {
            console.log('count changed');
        },
        immediate: true
    }
}

3、异步处理 (handler):watch 的回调函数是异步执行的,这意味着如果有多个值在短时间内发生变化,回调函数只会在这些变化结束后执行一次。

watch: {
  searchText: function (val) {
    this.searching=true
    setTimeout(()=> {
      this.searchData(val)
      this.searching=false
    }, 500)
  }
}

在这个例子中,我们监听了 searchText 属性,并在数据变化后延迟 500 毫秒执行搜索操作。

4、使用 watch 观察器实现自动保存

data() {
  content: ''
},
watch: {
  content: function (val) {
    localStorage.setItem('content', val)
  }
}

在这个例子中,我们监听了 content 属性,并在数据变化时自动保存到本地存储中。

应用场景介绍

watch 监听器还有许多其他的应用场景,例如:

  • 在表单输入时进行验证,并显示错误消息
  • 在表格中进行排序和过滤
  • 在地图上实时显示用户位置
  • 监听路由变化并执行相应操作
  • 监听窗口大小变化并调整布局
  • 监听滚动事件并实现懒加载
  • ……

1.在表单输入时进行验证,并显示错误消息

<template>
  <form>
    <label>
      Email:
      <input v-model="email" @keyup="validateEmail"/>
    </label>
    <p v-if="error">{{ error }}</p>
  </form>
</template>

<script>
export default {
  data() {
    return {
      email: '',
      error: ''
    }
  },
  watch: {
    email: {
      immediate: true,
      handler(val) {
        if (!val.includes('@')) {
          this.error='Invalid email address'
        } else {
          this.error=''
        }
      }
    }
  }
}
</script>

2.在地图上实时显示用户位置

<template>
  <div>
    <div id="map"></div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      userLocation: {
        lat: 0,
        lng: 0
      },
      map: null
    }
  },
  mounted() {
    this.map=new google.maps.Map(document.getElementById("map"), {
      center: { lat: 0, lng: 0 },
      zoom: 8
    });
    navigator.geolocation.getCurrentPosition(position=> {
      this.userLocation={
        lat: position.coords.latitude,
        lng: position.coords.longitude
      }
    });
  },
  watch: {
    userLocation: {
      deep: true,
      handler(val) {
        this.map.setCenter(val);
        new google.maps.Marker({
          position: val,
          map: this.map
        });
      }
    }
  }
}
</script>

在这个示例中,我们使用了 watch 来监听 userLocation 的变化,在用户位置发生变化时,使用 setCenter 方法将地图中心设置为用户当前位置,并使用 google maps API 在地图上添加一个标记,显示用户当前位置。

注意:这个例子需要引入 google maps 的 js 文件。

3、监听路由变化并执行相应操作

<template>
  <!-- 省略 -->
</template>

<script>
export default {
  watch: {
    $route(to, from) {
      // 根据路由变化执行相应操作
      if (to.path==='/home') {
        this.getHomeData()
      } else if (to.path==='/about') {
        this.getAboutData()
      }
    }
  },
  methods: {
    getHomeData() {
      // 获取首页数据
    },
    getAboutData() {
      // 获取关于页数据
    }
  }
}
</script>

4、监听窗口大小变化并调整布局

<template>
  <!-- 省略 -->
</template>

<script>
export default {
  data() {
    return {
      windowWidth: 0
    }
  },
  created() {
    this.windowWidth=window.innerWidth
  },
  watch: {
    windowWidth(newWidth, oldWidth) {
      // 监听窗口大小变化并调整布局
      if (newWidth < 768) {
        // 小屏幕布局
      } else {
        // 大屏幕布局
      }
    }
  },
  mounted() {
    window.addEventListener('resize', ()=> {
      this.windowWidth=window.innerWidth
    })
  }
}
</script>

5、监听滚动事件并实现懒加载

<template>
  <div class="container" ref="container" @scroll="handleScroll">
    <img v-for="(item, index) in images" :key="index" :src="item.src" v-show="item.isLoaded" />
  </div>
</template>

<script>
export default {
  data() {
    return {
      images: [
        { src: 'image1.jpg', isLoaded: false },
        { src: 'image2.jpg', isLoaded: false },
        { src: 'image3.jpg', isLoaded: false },
        // ...
      ]
    }
  },
  mounted() {
    // 初始化加载第一屏图片
    this.lazyLoad();
  },
  methods: {
    handleScroll() {
      this.lazyLoad();
    },
    lazyLoad() {
      const container=this.$refs.container;
      const imageList=Array.from(container.querySelectorAll('img'));
      // 遍历图片列表,如果图片进入了可视区域,就加载
      imageList.forEach(img=> {
        if (this.isInViewport(img)) {
          img.src=img.dataset.src;
          img.isLoaded=true;
        }
      });
    },
    isInViewport(img) {
      // 获取图片相对于视口的位置
      const rect=img.getBoundingClientRect();
      // 判断图片是否进入了可视区域
      return rect.top < window.innerHeight && rect.bottom > 0;
    }
  },
  watch: {
    images: {
      handler: function(newVal, oldVal) {
        // 每当图片加载完成时,就移除已加载图片的 isLoaded 属性
        newVal.forEach((item, index)=> {
          if (item.isLoaded) {
            this.$set(this.images[index], 'isLoaded', false);
          }
        });
      },
      deep: true
    }
  }
}
</script>

注意:需要注意的是,在这个案例中,因为images数组中的对象被改变了,所以需要设置deep: true来监听对象

总之,watch 是一个非常强大和灵活的功能,它可以在数据变化时执行任何操作,并且可以与 computed 计算属性配合使用,来实现更复杂的逻辑。

computed 和 watch 的区别

watch和computed都可以监听Vue实例中的数据变化,但是它们有着明显的不同。

watch

computed

用于监听某个特定的数据变化。

用于计算属性,可以计算出一个新的值。

每次数据变化都会触发回调函数。

仅在相关依赖发生改变时才会触发重新计算。

适用于异步操作或复杂逻辑。

适用于简单计算。

不可以在HTML模板中使用

可以在HTML模板中使用

没有返回值

有返回值/getter

可以修改data中的数据

也可以使用setters 修改 data 中的数据

总之,如果你需要在数据变化时执行异步操作或复杂逻辑,使用watch是更好的选择;如果你需要在数据变化时计算出一个新值,使用computed是更好的选择。

关于watch的性能

watch的性能取决于你的代码实现方式和监听的数据量。

  • 监听的数据量:如果你监听了大量的数据,那么 watch 的性能可能会受到影响。
  • 代码实现:如果你在 watch 回调函数中执行了复杂的逻辑或异步操作,那么 watch 的性能可能会受到影响。
  • 如果你只是需要在数据变化时执行一些简单的操作,那么 watch 的性能应该是可以接受的。

所以,在使用watch时,应该注意监听的数据量,并且在watch回调函数中尽量少执行复杂的逻辑.总之,watch监听数据更新并执行回调函数,性能会受到监听数据量和回调函数实现方式的影响,如果有性能问题,应该优化监听的数据量和回调函数的实现方式.

结束

今天的文章就介绍到这里,关于 watch 的用法你学会了,希望今天的文章能帮助到你,感谢你的阅读。如果你喜欢我的分享,别忘了点赞转发,让更多的人看到,最后别忘记点个关注,你的支持将是我分享最大的动力,后续我会持续输出更多内容,敬请期待。

推荐阅读

Vue3 学习笔记,Vue 简介及如何引入 Vue3 框架(一)

作者 | 峰华 责编 | 梦依丹
出品 | 峰华的个人博客

在前端这个无奇不有的世界里,有些网站不是正常垂直滚动的,而是横向滚动的:


那么在没法把鼠标滚轮横过来的前提下(苹果除外),能否实现网页横向滚动呢?我们来写代码试试。先看一下最终效果,这里我用鼠标的滚轮垂直滚动,页面是横向滚动的。

要实现这个功能,只需要一点点的 JS 代码。


编写 HTML 结构


先看一下 HTML 结构,很简单,就是三个模拟全屏页面的 div,class 都是 page,然后放在一个 class 名为 container 的 div 容器中:

  • <main> <div class="container"> <div class="page">Page1</div> <div class="page">Page2</div> <div class="page">Page3</div> </div></main>


    编写 CSS 样式

    对于样式,container 容器设置为 flex 布局,并且显示横向滚动条:

    • .container { display: flex; overflow-x: scroll;}

      里面每一个页面元素的宽高都设置为占满浏览器可视区域的 100%,并且在 flex 布局中,不自动收缩,再分别给他们设置不同的背景色,用于区分:

      • .page { width: 100vw; height: 100vh; flex-shrink: 0;}
        .page:nth-child(1) { background: hsl(140deg, 50%, 50%);}
        .page:nth-child(2) { background: hsl(210deg, 50%, 50%);}
        .page:nth-child(3) { background: hsl(270deg, 50%, 50%);}


        实现横向滚动


        接下来我们使用 JS 实现横向滚动,首先获取 container 容器:

        let container=document.querySelector(".container");

        给它添加一个 “wheel” 事件,这个是监听鼠标滚轮的滚动,在滚动时,先阻止默认的滚动事件,然后让容器水平横向移动,这里利用到了 scrollLeft 属性,让容器的内容向左移动,这里只需要加上滚轮垂直滚动的距离差值就可以了,也就是 event 对象中的 deltaY 属性:

        • container.addEventListener("wheel", (event)=> { event.preventDefault(); container.scrollLeft +=event.deltaY;});


          兼容性

          wheel 事件的兼容性可以参考 caniuse 提供的数据:


          总结

          这样就实现横向滚动了,重点是利用了 “wheel” 事件监听鼠标滚轮滚动,然后获取滚动距离差值,把它加到可以滚动的容器的 scrollLeft 属性中,你学会了吗?

          源码地址:https://github.com/zxuqian/html-css-examples/tree/master/38-horizontal-scrolling

          原文地址:https://zxuqian.cn/docs/videos/effects/js-horizontal-scroll-effect/

021年你需要知道的HTML标签和属性

Web开发人员都在广泛的使用HTML。无论你使用什么框架或者选择哪个后端语言,框架在变,但是HTML始终如一。尽管被广泛使用,但还是有一些标签或者属性是大部分开发者不熟知的。虽然现在有很多的模版引擎供我们使用,但是乐字节教育的老师和我们说还是需要尽可能的熟练掌握HTML内容,就像CSS一样。

在我看来,最好尽可能使用HTML特性来实现我们的功能,而不是使用JavaScript实现相同的功能,尽管我承认编写HTML可能会是重复的和无聊的。

尽管许多开发人员每天都在使用HTML,但他们并没有尝试改进自己的项目,也没有真正利用HTML的一些鲜为人知的特性。

下面这5个通过HTML标签/属性实现的功能我觉得需要了解一下:

图片懒加载

图片懒加载可以帮助提升网站的性能和响应能力。图片懒加载可以避免立即加载那些不在屏幕中立即显示的图片素材,当用户滚动临近图片时再去开始加载。

换言之,当用户滚动到图片出现时再进行加载,否则不加载。这就降低了屏幕内容展示过程中的图片素材的请求数量,提升了站点性能。

往往我们都是通过javascript来实现的,通过监听页面滚动事件来确定加载对应的资源。但是,在不完全考虑兼容性的场景下,我们其实可以直接通过HTML来直接实现。

注:本篇的提到的标签和属性的兼容性需要大家根据实际场景来选取是否使用

可以通过为图片文件添加loading="lazy"的属性来实现:


输入提示

当用户在进行输入搜索功能时,如果能够给出有效的提示,这会大大提升用户体验。输入建议和自动完成功能现在到处可见,我们可以使用Javascript添加输入建议,方法是在输入框上设置事件侦听器,然后将搜索到的关键词与预定义的建议相匹配。

其实,HTML也是能够让我们来实现预定义输入建议功能的,通过<datalist>标签来实现。需要注意的是,使用时这个标签的id属性需要和input元素的list属性一致。


Picture标签

你是否遇到过在不同场景或者不同尺寸的设备上面的时候,图片展示适配问题呢?我想大家都遇到过。

针对只有一个尺寸的图片素材的时候,我们往往可以通过CSS的object-fit属性来进行裁切适配。但是有些时候需要针对不同的分辨率来显示不同尺寸的图片的场景的时候,我们是否可以直接通过HTML来实现呢?

HTML提供了<picture>标签,允许我们来添加多张图片资源,并且根据不同的分辨率需求来展示不同的图片。


我们可以定义不同区间的最小分辨率来确定图片素材,这个标签的使用有些类似<audio>和<video>标签。

Base URL

当我们的页面有大量的锚点跳转或者静态资源加载时,并且这些跳转或者资源都在统一的域名的场景时,我们可以通过<base>标签来简化这个处理。

例如,我们有一个列表需要跳转到微博的不同大V的主页,我们就可以通过设置来简化跳转路径


<base>标记必须具有href和target属性。

页面重定向(刷新)

当我们希望实现一段时间后或者是立即重定向到另一个页面的功能时,我们可以直接通过HTML来实现。

我们经常会遇到有些站点会有这样一个功能,“5s后页面将跳转”。这个交互可以嵌入到HTML中,直接通过<meta>标签,设置http-equiv="refresh"来实现


这里content属性指定了重定向发生的秒数。值得一提的是,尽管谷歌声称这种形式的重定向和其他的重定向方式一样可用,但是使用这种类型的重定向其实并不是那么的优雅,往往会显得很突兀。

因此,最好在某些特殊的情况下使用它,比如在长时间用户不活动之后再重定向到目标页面。

后记

HTML和CSS是非常强大的,哪怕我们仅仅使用这两种技术也能创建出一些奇妙的网站。虽然它们的使用量很大很普遍,还是有很多的开发者并没有真正的深入了解他们,还有很多的内容需要我们深入的去学习和理解,实践,有很多的技巧等待着我们去发现。

文章转载至乐字节

最后给大家推荐几个b站超详细的Java自学课:

Servlet入门教程BV1D5411373E

Vue、Vuejs教程,BV19V41177od

SpringBoot+Vue项目实战BV1o64y117qQ