# watch
export function initState(vm: Component) {
if (opts.watch && opts.watch !== nativeWatch) {
initWatch(vm, opts.watch);
}
}
初始化watch也是在initState中,这里做了个判断是为了去除 firfox中的原生 watch 方法。
function initWatch(vm: Component, watch: Object) {
for (const key in watch) {
const handler = watch[key];
if (Array.isArray(handler)) {
for (let i = 0; i < handler.length; i++) {
createWatcher(vm, key, handler[i]);
}
} else {
createWatcher(vm, key, handler);
}
}
}
这里会对watch遍历,获取到handler,之后调用createWatcher,如果是数组,对每一个子元素进行调用。
function createWatcher(
vm: Component,
expOrFn: string | Function,
handler: any,
options?: Object
) {
if (isPlainObject(handler)) {
options = handler;
handler = handler.handler;
}
if (typeof handler === "string") {
handler = vm[handler];
}
return vm.$watch(expOrFn, handler, options);
}
createWatcher函数主要是调用$watch函数,在调用之前会做一层处理,因为我们定义 watch 的时候可能传函数或者对象,所以做了一层判断获取到用户定义的函数。
// 如果传递的是对象,
// options={
// deep: true,
// handler() {},
// }
// handler=function(){}
export default {
watch: {
name: {
deep: true,
handler() {},
},
},
};
// 如果传递的是字符串,则会从实例vm中获取到对应的methods
// handler=function method1(){}
export default {
watch: {
name: "method1",
},
};
$watch定义在stateMixin中:
Vue.prototype.$watch = function (
expOrFn: string | Function,
cb: any,
options?: Object
): Function {
// 需要获取实例,所有没有静态方法
const vm: Component = this;
if (isPlainObject(cb)) {
return createWatcher(vm, expOrFn, cb, options);
}
options = options || {};
// 用户watcher
options.user = true;
const watcher = new Watcher(vm, expOrFn, cb, options);
if (options.immediate) {
const info = `callback for immediate watcher "${watcher.expression}"`;
pushTarget();
invokeWithErrorHandling(cb, vm, [watcher.value], vm, info);
popTarget();
}
// 取消监听
return function unwatchFn() {
watcher.teardown();
};
};
$watch函数也很简单,就是创建了watcher实例,传递了user=true,如果有immediate参数,则执行传递过来的cb,最后返回unwatchFn函数。
class Watcher {
teardown() {
if (this.active) {
if (!this.vm._isBeingDestroyed) {
remove(this.vm._watchers, this);
}
let i = this.deps.length;
while (i--) {
this.deps[i].removeSub(this);
}
this.active = false;
}
}
}
deps数组中移除当前的watcher。