虽然Vue.js
为我们提供了有用的computed
, 但在某些场景下, 仍然还是需要使用到watch
.
默认情况下,
watch
只在被监听的属性值发生变化时执行.
例如:
export default {
data: () => ({
dog: ""
}),
watch: {
dog(newVal, oldVal) {
console.log(`Dog changed: ${newVal}`);
}
}
};
如上代码所示, 只有当dog
的值有发生改变时, watch
中的dog
函数才会执行.
watch options
immediate
但是, 在某些情况下, 你可能需要在创建组件后立即运行监听程序.
当然, 你可以将逻辑迁移至methods
中, 然后从watch
和created
钩子函数中分别调用它, 但有没有更简单一点的办法呢?
你可以在使用watch
时, 使用immediate: true
选项, 这样它就会在组件创建时立即执行.
export default {
data: () => ({
dog: ""
}),
watch: {
dog: {
handler(newVal, oldVal) {
console.log(`Dog changed: ${newVal}`);
},
immediate: true
}
}
};
deep
watch
中还有一个属性: deep
, 默认值为: false
, 即是否需要开启深度监听.
例如:
export default {
data: () => ({
obj: {
hello: 'james'
}
}),
watch: {
obj: {
handler(newVal, oldVal) {
console.log(`obj changed: ${newVal}`);
},
immediate: true,
deep: true
}
}
};
deep
即深入观察, 监听器会层层遍历, 给对象的所有属性(及子属性)添加监听器. 这样做无疑会有很大的性能开销, 修改obj
中任何一个属性都会触发监听器中的处理函数.
若只想监听obj
中的某个属性, 可以使用字符串监听形式.
export default {
data: () => ({
obj: {
hello: 'james'
}
}),
watch: {
'obj.hello': {
handler(newVal, oldVal) {
console.log(`obj changed: ${newVal}`);
},
immediate: true,
deep: false
}
}
};
动态添加watch
Vue源代码中$watch
的实现:
Vue.prototype.$watch = function (
expOrFn,
cb,
options
) {
var vm = this;
if (isPlainObject(cb)) {
return createWatcher(vm, expOrFn, cb, options)
}
options = options || {};
options.user = true;
var watcher = new Watcher(vm, expOrFn, cb, options);
if (options.immediate) {
try {
cb.call(vm, watcher.value);
} catch (error) {
handleError(error, vm, ("callback for immediate watcher \"" + (watcher.expression) + "\""));
}
}
return function unwatchFn () {
watcher.teardown();
}
};
基于此, 我们可以将上面的示例代码修改为 动态添加watch
, 例如:
export default {
data: () => ({
obj: {
hello: 'james'
}
}),
mounted(){
this.$watch('obj.hello', this.handler, {
immediate: true,
deep: false
})
},
methods: {
handler(newVal, oldVal) {
console.log(`obj changed: ${newVal}`);
}
}
};
Warning:
正常情况下, 不推荐使用$watch
来动态添加watch
, 因为你还需要手动注销watch监听事件
注销watch
若使用动态添加watch
, 就需要手动注销了.
从源代码中, 可以看出: this.$watch
调用后会有一个返回值, 通过调用此返回值, 即可注销watch.
修改代码如下:
let unWatch = null
export default {
data: () => ({
obj: {
hello: 'james'
}
}),
mounted(){
unWatch = this.$watch('obj.hello', this.handler, {
immediate: true,
deep: false
})
},
methods: {
handler(newVal, oldVal) {
console.log(`obj changed: ${newVal}`);
}
},
beforeMount(){
unWatch()
unWatch = null
}
};