首先明确一个概念,Vue 是可以监听到 多层级数据改变的,且可以在页面上做出对应展示。但是 Vue 提供的 watch 方法,默认是不提供 深度监听的( deep 默认为 false,也就是不开启深度监听)
举例
这是例子的html 片段:点击对应按钮之后,a 或 b 分别自增1
{{numbers.a}}
{{numbers.b}}
1、监听对象内部属性变化:当我只改变a的时候,只监听a的变化
点击按钮,发现 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就会执行监听动作,下面的代码就是证明
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 内部属性的改变。
{{numbers.a}}
{{numbers.b}}
分别点击两个按钮,能看到两个属性都发生了改变,且控制台上输出了两次监听信息,这就说明了,配置 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)