vue的watch

207 阅读3分钟

watch

简介:虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。

注意点不应该使用箭头函数来定义 watcher 函数

watch中的几个常见属性:

1. handler: 定义监听到键名发生变化后执行的回调

2. immediate:因为默认是监听到数据改变时,才会执行handler回调;如果我们想一开始就让他的变化回调handler执行,就需要使用`immediate: true`

3. deep:可以深度监听整个键名内部的所有属性

1. 基本使用

  • 被监听的data中的键名对应键值类型String | Function | Object | Array
<!-- 基本使用示例1: -->
<body>
    <div id="app">
        <input v-model="count" />
    </div>
    <script>
        new Vue({
            el: '#app',
            data: {
                count: 10,
            },
            watch: {
               // watch中实时监听的是 data中的 count键名,count键对应的键值是一个回调函数
               // 回调函数接受两个参数,newVal是count变化后的值,oldValue是count变成newValue的前一个值
                count: function (newVal, oldVal) {
                    console.log(`new: %s, old: %s`, newVal, oldVal);
                }
            }
        })
    </script>
</body>

<!-- 基本使用示例2:监听到变化之后可以操作 -->
<div>
      <p>FullName: {{fullName}}</p>
      <p>FirstName: <input type="text" v-model="firstName"></p>
</div>
<script>
      new Vue({
        el: '#root',
        data: {
          firstName: 'Dawei',
          lastName: 'Lou',
          fullName: ''
        },
        watch: {
          firstName(newName, oldName) {
            // 监听到firstName变化,操作之后赋值给fullName
            this.fullName = newName + ' ' + this.lastName;
          }
        } 
      })
</script>

2. watch属性使用

// 示例2:监听data中的键名所对应的键值的各种类型
var vm = new Vue({
  data: {
    a: 1,
    b: 2,
    c: {
       title:'my-blog',
        categories:[]
    },
    d: 4,
    e: {
      f: {
        g: 5
      }
    }
  },
  watch: {
    
    a: function (newVal, oldVal) {
        console.log(`new: %s, old: %s`, newVal, oldVal);
    },
    // 可以是方法名
    b: 'someMethod',
    
    c: function (newVal, oldVal) {
        console.log("如果c对象中的某个属性发生了变化,我们这种直接监听c对象是监听不到变化的,因为c对象的指向并没有发生改变");
    },
    
    // 下面监听方式的缺点是,只要修改c对象中的任何一个属性(无论嵌套多深的属性),都会执行handler;这样会造成更多的性能开销
    c: {
      handler: function (val, oldVal) { /* ... */ },
      deep: true
    },
    
    // 只监听某个对象的特定属性,'c.title' 字符串写法;这种方式的优点弥补了深度监听整个对象而造成了更多的性能开销
    'c.title': function(newVal, oldVal){
      
    }
    
    // 因为默认是监听到数据改变时,才会执行handler回调;如果想一开始就让他的变化回调handler执行,就需要使用`immediate: true`
    d: {
      handler: 'someMethod',
      immediate: true
    },
    
    // 你可以传入回调数组,当e发生变化时,这一组回调函数它们会被逐一调用;感觉有点像观察者模式
    e: [
      'handle1',
      function handle2 (val, oldVal) { /* ... */ },
      {
        handler: function handle3 (val, oldVal) { /* ... */ },
        /* ... */
      }
    ],
  }
})
vm.a = 2 // => new: 2, old: 1

3. watch中的异步操作

可以在watch中执行复杂的异步操作等;这些是computed不能胜任的。具体可以参考官网的案例

4. vm.$watch实例方法

注意:在变更 (不是替换) 对象或数组时,旧值将与新值相同,因为它们的引用指向同一个对象/数组。Vue 不会保留变更之前值的副本

语法vm.$watch( expOrFn, callback, [options] )

  • expOrFnString Function,可以是监听的字符串键名,或者监听函数(就像监听一个未被定义的计算属性)

  • callbackFunction Object 监听的键名发生变化后的回调

  • options: { handler | immediate | deep)

// 示例1:
// 键路径
vm.$watch('a.b.c', function (newVal, oldVal) {
 // 做点什么
})


// 示例2:
// 函数
vm.$watch(
 function () {
   // 表达式 `this.a + this.b` 每次得出一个不同的结果时
   // 处理函数都会被调用。
   // 这就像监听一个未被定义的计算属性
   return this.a + this.b
 },
 function (newVal, oldVal) {
   // 做点什么
 }
)

5. watch注销

vm.$watch: 返回一个取消观察函数,用来停止触发回调

注意:组件选项中的watch中可以随着组件的销毁而销毁,而实例方法的vm.$watch(),我们需要手动销毁

var unwatch = vm.$watch('a', callback);
// 停止触发回调
unwatch()

本文使用 mdnice 排版