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

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

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

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

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

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

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

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

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

在 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)
  }
}

一些高级用法介绍

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

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

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

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

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

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

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

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

使用 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 的用法你学会了,希望今天的文章能帮助到你,感谢你的阅读。

责任编辑:姜华 来源: 今日头条
相关推荐

2021-11-17 08:24:47

Vue3 插件Vue应用

2023-06-02 07:32:34

localStorage​监听

2023-11-16 08:29:26

2023-11-28 09:03:59

Vue.jsJavaScript

2021-12-29 07:51:21

Vue3 插件Vue应用

2021-12-01 08:11:44

Vue3 插件Vue应用

2021-12-02 05:50:35

Vue3 插件Vue应用

2021-11-30 08:19:43

Vue3 插件Vue应用

2021-12-07 05:44:45

Vue 3 Watch WatchEffect

2021-11-16 08:50:29

Vue3 插件Vue应用

2023-12-11 07:34:37

Computed计算属性Vue3

2021-12-08 09:09:33

Vue 3 Computed Vue2

2023-12-06 07:43:56

Vue如何定义事件

2022-07-14 08:22:48

Computedvue3

2022-06-09 08:28:27

Vue3watchwatchEffec

2023-11-29 08:49:31

Vue.jsData 函数

2021-11-26 05:59:31

Vue3 插件Vue应用

2022-06-29 16:59:21

Vue3Vue2面试

2021-09-03 08:23:21

Vue 插槽子组件

2022-07-20 11:13:05

前端JSONVue3
点赞
收藏

51CTO技术栈公众号