watch的调用方式
常见的场景有下面这几个:
1. 数据变 → 使用数据的视图变(负责敦促视图更新的render-watcher)
vue实例或者component组件通过调用$mount方法生成render函数(不管实例当中使用的是el/template,最终都会编译成render),在初始化vue实例或者组件的时候,会为render函数绑定watcher监听事件。
文件路径:src/core/instance/lifecycle.js文件下,对渲染函数的绑定。下面将会详细讲wather的绑定
2. 数据变 → 使用数据的计算属性变 → 使用计算属性的视图变(执行敦促计算属性更新的computed-watcher)
文件路径:src/core/instance/state.js文件下
3. 数据变 → 开发者主动注册的watch回调函数执行(用户注册的普通watcher(watch-api或watch属性))
文件路径:src/core/instance/state.js文件下
watch的使用
watch: {
name: [function() {
console.log('kkkkkkkkk');
}, function() {
console.log('gggggggggg');
}], // 数组
name: function() {
console.log('ssssss');
}, // 普通函数
name: {
handler: function (val, oldVal) {
},
deep: true
}, // 对象
name: {
handler: 'testName' // testName对应methods里面的方法名
}
},
watcher 文件的说明
watcher是放在src/core/observe/watcher.js里面
1. watcher初始化,即constructor方法
2. get函数
get函数里面调用了getter,以下是对get的说明
- 一个data中的属性对应对应一个dep, 一个dep中可能包含多个watcher(模板中可能使用了计算属性、组件等,都有可能引起多个watcher)
- 模板中一个非事件表达式对应一个watcher, 一个watcher中可能包含多个dep(表达式中包含了几个data属性, 或者是render函数中,用了多个属性)
getter 函数,有3种形式。
第一种,是render函数
updateComponent = () => {
vm._update(vm._render(), hydrating)
}
第二种: 计算属性的函数
watchers[key] = new Watcher(
vm,
getter || noop,
noop,
computedWatcherOptions
)
第二种,字符串,获取值的的字符串,譬如下面调用
当这种方式使用watcher的时候
watch: {
name: function() {
console.log('kkkkkkkkk');
}
}
那么生成watcher的时候,通过parsePath生产一个获取表达式值的函数
parsePath(expOrFn)
getter函数的执行原理(getter函数里面用到了那些数据,就给这个数据的dep加上watcher。同时也给watcher加上dep)
1、 在生成watcher的时候,对props、data都进行了双向数据绑定,即有get和set方法。一个data属性对应一个订阅器(dep)
2、 在get的方法的里面,有以下操作,把watcher添加到dep里面,也把dep添加到watcher里面
if (Dep.target) {
dep.depend()
if (childOb) {
childOb.dep.depend() // 如果有child, 也要给child属性加watcher
if (Array.isArray(value)) {
dependArray(value)
}
}
}
3. 不管是哪一种方式,调用this.getter的时候,都会获取getter里面的获取里面的属性的值譬如this.name来获取name的值。这时候就会调用数据绑定中的get方法
就会执行2上面的方法,订阅器和watcher会相互添加。