首先明确一个概念,Vue 是可以监听到 多层级数据改变的,且可以在页面上做出对应展示。但是 Vue 提供的 watch 方法,默认是不提供 深度监听的( deep 默认为 false,也就是不开启深度监听)

举例

这是例子的html 片段:点击对应按钮之后,a 或 b 分别自增1

<div id="root">
  {{numbers.a}}
  <button @click='numbers.a++'>a++</button>
  <br><br><br>
  {{numbers.b}}
  <button @click='numbers.b++'>b++</button>
</div>

 1、监听对象内部属性变化:当我只改变a的时候,只监听a的变化


<script>
  const vm = new Vue({
    el: '#root',
    data() {
      return {
        numbers: {
          a: 1,
          b: 1
        }
      }
    },
    watch: {
      a: {
        handler(newValue, oldValue) {
          console.log(newValue, oldValue)
          console.log('numbers正在被侦听')
        },
        // deep: true,
        // immediate: true
      }
    }
  })

</script>

 点击按钮,发现 a 是新增了,但是控制台上没有输出,这就表明了,此时 a 是没有被监听到的。那么,当我开启 deep 之后是什么情况呢?实验证明,开启之后,a还是未被监听到的,这就表示了,此时监听 a 是监听不到的。

由此得出:当存在多层属性嵌套时,直接监听内层属性时无法做到的。因为此时vm上存在的只有data内的一级属性,外加计算属性,data内层属性是 observe 取的

2、监听对象内部属性变化:当我只改变a值的时候,通过最外层的属性,监听到内部改变的属性

watch: {
  'numbers.a': {
    handler(newValue, oldValue) {
      console.log(newValue, oldValue)
      console.log('numbers正在被侦听')
    },
    deep: true,
    // immediate: true
  }
}

在这里,通过最外层的 numbers 属性,来访问到内部的 改变的 a属性,然后监听 numbers.a,此时,我们发现,无论是否开启 deep:true ,只要改变了a的值,都会触发监听动作。但是改变了b之后,是不会触发监听动作的

 

结论:可以通过 外层属性访问内层属性的结构,来监听内层属性

 3、监听整个 numbers 中 每个属性的变化

按照监听 a 属性的写法,如果我们要监听 整个 numbers 属性,那我们可以直接把 监听 属性a 的代码复制一份,然后把监听对象改成b就行

watch: {
  'numbers.a': {
    handler(newValue, oldValue) {
      console.log(newValue, oldValue)
      console.log('numbers.a正在被侦听')
    },
  },
  'numbers.b': {
    handler(newValue, oldValue) {
      console.log(newValue, oldValue)
      console.log('numbers.b正在被侦听')
    },
  }
}

 

 事实证明这样是可行的,但是如果我的 numbers 内部,存在数以百计的属性,那么我需要怎么监听整个 numbers 的改变?总不能每个属性都单独写一个监听的动作吧,那代码该有多少重复的?所以监听整个 numbers 肯定是有别的方法的。

4、直接监听整个 numbers 属性的变化

watch: {
  numbers: {
    handler(newValue, oldValue) {
      console.log(newValue, oldValue)
      console.log('numbers正在被侦听')
    },
  },
}

从结果可以看出,即使 numbers 内部的 a、b 都已经改变了,但是并未监听到 numbers 的改变。

这是因为,这样写的话,numbers  是 data 中的key,那 value 则是numbers的内存地址。 vue 监视的是 numbers ,也就是说,vue 此时监视的是 numbers 对象属性的 内存地址,只要内存地址不改变,则不会监听 numbers 的改变,即使改变了 numbers 内部的属性值,但是 numbers 对应的内存地址,所以这样写的时候 vue 是不会监视 numbers 内部的属性。

 如果,我直接改变了 numbers 的内存地址,那么vue就会执行监听动作,下面的代码就是证明

<button @click='numbers = {a:"qqq",b:"www"}'>b++</button>

const vm = new Vue({
  el: '#root',
  data() {
    return {
      numbers: {
        a: 1,
        b: 1
      }
    }
  },
  watch: {
    numbers: {
      handler(newValue, oldValue) {
        console.log(newValue, oldValue)
        console.log('numbers正在被侦听')
      },
    },
  }
})

点击按钮之后,直接改变了整个 numbers,这样就在内存中重新开辟了一块,numbers 也就指向了一个新的地址,那么vue就执行了监听动作,控制台输出了监听参数

 但是我们需要的肯定不是这样,我们需要的是,在内存地址不改变的情况下,改变 numbers 内部的属性,此时 vue 也能监听到 内部属性的改变。

deep:true  开启深层属性监听,默认为 false 不监听

还是以上面的代码为例,配置  deep:true  之后,单独改变 numbers 内部的属性,看看能否监听到 numbers 内部属性的改变。

<div id="root">
  {{numbers.a}}
  <button @click='numbers.a++'>a++</button>
  <br><br><br>
  {{numbers.b}}
  <button @click='numbers.b++'>b++</button>
</div>

<script>
  Vue.config.productionTip = false

  const vm = new Vue({
    el: '#root',
    data() {
      return {
        numbers: {
          a: 1,
          b: 1
        }
      }
    },
    watch: {
      numbers: {
        handler(newValue, oldValue) {
          console.log(newValue, oldValue)
          console.log('numbers正在被侦听')
        },
        deep: true
      },
    }
  })
</script>

分别点击两个按钮,能看到两个属性都发生了改变,且控制台上输出了两次监听信息,这就说明了,配置 deep:true 之后,在改变内部属性之后,vue 也是能监听到的 

 

通过实例改变多层级内部属性,vue能监听到 

 还是上面的例子,但是 不配置 deep:true,然后通过 vm 访问 numbers.a ,且改变 属性 a 的值,看看页面效果

 可以看到,通过实例改变属性 a 的值之后,页面上也展示了新的数据,在这就证明了,vue 确实是能自动监听到 多层级的内部属性的改变的。但是 watch 内部监听的函数没有执行

当我开启 deep:true 之后,然后在改变 属性 a 的值,再来看看页面展示和控制台输出

 这里可以看到,vue还是是能监听到内部属性的改变的,且一旦开启了 deep:true 之后,在 watch 中 监听的多级属性在 内部属性 改变之后,也能被 watch 监听到了。

本章小结

深度监视:

        1、Vue实例默认会监听对象内部值的改变且页面上对应改变,但是Vue的watch(vm.$watch)默认不监听对象内部值的改变

        2、配置deep:true,可以在 watch($watch) 中监听 对象内部的值的改变

备注:使用 watch 时,需要根据数据结构,判断是否采取深度监听(deep:true) 

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐