web123456

Handwritten Vue2.0 Responsive Principle

class Vue { constructor(options) { this.$options = options this.$data = options.data // Rewrite the array method let arrayPrototype = Array.prototype const methods = ['pop', 'push', 'shift', 'unshift'] this.proto = Object.create(arrayPrototype) methods.forEach(method => { this.proto[method] = function() { arrayPrototype[method].call(this, ...arguments) } }) // Responsive this.observe(this.$data) // Test code // new Watcher(this, 'test') // // Create a compiler // new Compile(, this) if (options.created) { options.created.call(this) } } // Recursive traversal to responsive objects passed in observe(value) { if (!value || typeof value !== 'object') { return } if (Array.isArray(value)) { Object.setPrototypeOf(value, this.proto) } Object.keys(value).forEach(key => { // Responsive processing of keys this.defineReactive(value, key, value[key]) this.proxyData(key) }) } // Define the data in the attribute proxy data on the Vue root, so that the data can be called through this proxyData(key) { Object.defineProperty(this, key, { get() { return this.$data[key] }, set(newVal) { this.$data[key] = newVal } }) } defineReactive(obj, key, val) { // Recursive response, processing nested objects this.observe(val) // Create a Dep instance: Dep and key correspond one to one const dep = new Dep() // Define attributes for obj Object.defineProperty(obj, key, { get() { // Add the pointing Watcher instance to Dep, this part is to collect dependencies Dep.target && dep.addDep(Dep.target) console.log('get') return val }, set(newVal) { if (newVal !== val) { val = newVal console.log('set') // (`${key} attribute has been updated`) dep.notify() // Notify view update } } }) } } // Dep: manages several watcher instances, which are one-to-one relationships with key class Dep { constructor() { this.deps = [] } addDep(watcher) { this.deps.push(watcher) } notify() { this.deps.forEach(watcher => watcher.update()) } } // Implement the update function to update class Watcher { constructor(vm, key, cb) { this.vm = vm this.key = key this.cb = cb // Point the current instance to Dep.target = this this.vm[this.key] Dep.target = null } update() { console.log(`${this.key}The attributes have been updated`) this.cb.call(this.vm, this.vm[this.key]) } }