vue--Vue的watch实现原理及watch实现方式
参考: https://www.jianshu.com/p/ffe50c5e3368
解释:
vm 调用 $watch
后,首先调用 observe
函数 创建 Observer
实例观察数据,Observer
又创建 Dep
, Dep
用来维护订阅者。然后创建 Watcher
实例提供 update
函数。一旦数据变动,就层层执行回调函数。
重点:
- 首先确认 watch是一个对象,一定要当成对象来用。 对象就有键,有值。
- 对于组件选项外定义的监听函数,需要手动调用unWatch()函数进行注销 // ???喵喵
- watch这个特性,是针对当前组件中的初始值来进行判断的.....在初始化的时候,这个data_list已经被修改了,此时watch已经被触发。
var vm = new Vue({
data: {
a: 1,
b: 2
},
watch: {
a: function (val, oldVal) {
console.log('new: %s, old: %s', val, oldVal)
},
// 方法名
b: 'someMethod',
// 选项的对象
c: {
handler: function (val, oldVal) { /* ... */ },
deep: true,// 是否深入监听。(一般监听时是不能监听到对象属性值的变化的,数组的值变化可以听到。)
immediate: true // 设置之后 是否以当前的初始值执行handler的函数
}
}
})
手动使用$watch设置初始值和注销watch
我们在初始化的时候,这个data_list已经被修改了,此时watch已经被触发。解决方法如下:
created: function() {
axios.get(url).then(function(response){
vm.data_list = response.data
}
// 这样watch的初始值就不再是原来的空数组了,而是我们赋值之后的data_list了
this.$watch('data_list', function(){this.do_not_save = true}, {deep: true})
}
但是,如果我们使用下面这样的方式写 watch,那么就要手动注销了,这种注销其实也很简单
const unWatch = app.$watch('text', (newVal, oldVal) => {
console.log(`${newVal} : ${oldVal}`);
})
unWatch(); // 手动注销watch
替代deep使用的节省性能开销方案
deep的意思就是深入观察,监听器会一层层的往下遍历,给对象的所有属性都加上这个监听器,但是这样性能开销就会非常大了,任何修改obj里面任何一个属性都会触发这个监听器里的 handler。
优化,我们可以是使用字符串形式监听。
watch: {
'obj.a': {
handler(newName, oldName) {
console.log('obj.a changed');
},
immediate: true,
// deep: true
}
}