Vue2 core Principle (simple version)- Watch function realization
What is a watch used for?
Vue provides a more generic way to respond to changes in data with the Watch option. This approach is most useful when asynchronous or expensive operations need to be performed when data changes.
What is a watch?
An object whose key is the expression to observe and whose value is the corresponding callback function. The value can also be a method name, or an object that contains options. The Vue instance will call $watch() at instantiation time, iterating through each property of the Watch object. Document delivery
Example:
/ / define the watch
let vm = new Vue({
el: '#app'.data() {
return {
name: 'vue2'}},watch: {
name(newVal, oldVal) {
console.log(`watch name change form ${oldVal} to ${newVal}`); }}})/ / change the name
setTimeout(() = > {
vm.name = 'vue3'
}, 1000)
// Console prints
// watch name change form vue2 to vue3
Copy the code
How to make the watch?
- First, we’ll review the principles and implementation of vUE dependency collection, as shown in my previous article, dependency Collection.
The core principle is to add a custom Watcher to all the properties in the Watch object passed in Vue Options, collect the dependency of the corresponding property, and then notify not only its rendering Watcher but also the current custom Watcher when the dependency is updated. To call your defined callback, complete the logic inside the function.
- How to get newValue and oldValue when updating?
First, the default watcher binding is to execute the this.get method, so we do the same thing we did in rendering Watcher, which is to ‘touch’ the property, make the dependency feel dependent, add the subscriber, and then the value is the initial value. We log it to watcher, this.value = this.get(); . Each time the update method is called on watcher, we will call this.get again. Plus the this.value we recorded earlier, great, we have newValue and oldValue!
- Code implementation
A. Initialize the Watch object// Add $watch mixin export function stateMixin(Vue) { Vue.prototype.$watch = function (key, handler, options = {}) { const vm = this; options.user = true; new Watcher(vm, key, handler, options); }; } // Add a custom watcher to the passed watch function initWatch() { const vm = this; let watchs = vm.$options.watch; for (let key in watchs) { let handler = watchs[key]; if (Array.isArray(handler)) { for (let i = 0; i < handler.length; i++) { createWatcher(vm, key, handler[i]); }}else{ createWatcher(vm, key, handler); }}}function createWatcher(vm, key, handler) { vm.$watch(key, handler); } Copy the code
B. Modify the Watcher class to handle custom Watcher properties
// observer/watcher.js constructor(vm, exprOrFn, cb, options) { this.id = "watcher-" + id++; this.vm = vm; this.exprOrFn = exprOrFn; this.cb = cb; this.deps = []; this.depsId = new Set(a);this.options = options; this.user = !! options.user;if (typeof exprOrFn === "string") { this.getter = function () { let path = exprOrFn.split("."); let obj = path.reduce((pre, currentPath) = > { return pre[currentPath]; }, vm); return obj; }; } else { this.getter = exprOrFn; } this.value = this.get(); } get() { pushTarget(this); // Record the old value const value = this.getter.call(this.vm); popTarget(this); // Return the old value return value; } update() { // Update operations in VUE are asynchronous // I want to cache watcher and update it later queueWatcher(this); } run() { const oldValue = this.value; const newValue = this.get(); if (this.user) { this.cb(newValue, oldValue); // Remember to record the new value as the old value for the next time this.value = newValue; }}Copy the code
The complete code
Github.com/Sotyoyo/do-… Branch do – watch
The original link
If you are reading this article at a non-nuggets address, here is the original portal, your likes are the biggest support for me!
The 🎉
Next lecture, computed property implementation