I recently read the vue2.0 source code for responsive implementation. The following blog post will restore the vue2.0 implementation idea for responsive implementation through simple code.
Note that this is just a restoration of the implementation ideas. This example will not involve the details of the implementation, such as monitoring of data operations in the array, and object nesting. If you want to understand more detailed implementations, you can learn more about it by reading the source code observer folder and the state file in the instance folder.
First, we define the structure of implementing the vue object
class Vue { constructor(options) { this.$options = options; this._data = ; this.$el = (); } }
Step 1: Change the attributes below data to observable
Use the data object to listen for attributes get and set, and when there are data reading and assignment operations, the node's instructions are called, so that the most common = equal sign assignment can be triggered.
//Data hijacking, monitoring data changesfunction observer(value, cb){ (value).forEach((key) => defineReactive(value, key, value[key] , cb)) } function defineReactive(obj, key, val, cb) { (obj, key, { enumerable: true, configurable: true, get: ()=>{ return val }, set: newVal => { if(newVal === val) return val = newVal } }) }
Step 2: Implement a message subscriber
It's very simple. We maintain an array, and the subscriber will put the subscriber. Once notify is triggered, the subscriber will call his own update method.
class Dep { constructor() { = [] } add(watcher) { (watcher) } notify() { ((watcher) => ()) } }
Every time the set function is called, we trigger notify to achieve update
Then the question is. Who is the subscriber? Yes, it's the Watcher. . Once () iterates over the subscriber, that is, the Watcher, and calls his update() method
function defineReactive(obj, key, val, cb) { const dep = new Dep() (obj, key, { enumerable: true, configurable: true, get: ()=>{ return val }, set: newVal => { if(newVal === val) return val = newVal () } }) }
Step 3: Implement a Watcher
The implementation of Watcher is relatively simple, but it is actually what we need to perform when performing data changes.
class Watcher { constructor(vm, cb) { = cb = vm } update(){ () } run(){ () } }
Step 4: Get the dependency
In the above three steps, we implemented that data changes can trigger updates, and the problem now is that we cannot associate watcher with our data.
We know that after setting defineReactive properties on data, modifying the value on data will trigger set. Then we will trigger get when we take the value on data. So you can take advantage of this and execute the following render function first to know which data support is required for the update of the view and record it as a subscriber of the data.
function defineReactive(obj, key, val, cb) { const dep = new Dep() (obj, key, { enumerable: true, configurable: true, get: ()=>{ if(){ () } return val }, set: newVal => { if(newVal === val) return val = newVal () } }) }
Finally, let's look at using a proxy to bind our data access to data to vue objects.
_proxy(key) { const self = this (self, key, { configurable: true, enumerable: true, get: function proxyGetter () { return self._data[key] }, set: function proxySetter (val) { self._data[key] = val } }) } ().forEach(key => this._proxy(key))
The following is the complete code for the entire instance
class Vue { constructor(options) { this.$options = options; this._data = ; this.$el =(); ().forEach(key => this._proxy(key)) observer() watch(this, this._render.bind(this), this._update.bind(this)) } _proxy(key) { const self = this (self, key, { configurable: true, enumerable: true, get: function proxyGetter () { return self._data[key] }, set: function proxySetter (val) { self._data[key] = val } }) } _update() { ("I need to update"); this._render.call(this) } _render() { this._bindText(); } _bindText() { let textDOMs=this.$('[v-text]'), bindText; for(let i=0;i<;i++){ bindText=textDOMs[i].getAttribute('v-text'); let data = this._data[bindText]; if(data){ textDOMs[i].innerHTML=data; } } } } function observer(value, cb){ (value).forEach((key) => defineReactive(value, key, value[key] , cb)) } function defineReactive(obj, key, val, cb) { const dep = new Dep() (obj, key, { enumerable: true, configurable: true, get: ()=>{ if(){ () } return val }, set: newVal => { if(newVal === val) return val = newVal () } }) } function watch(vm, exp, cb){ = new Watcher(vm,cb); return exp() } class Watcher { constructor(vm, cb) { = cb = vm } update(){ () } run(){ () } } class Dep { constructor() { = [] } add(watcher) { (watcher) } notify() { ((watcher) => ()) } } = null; var demo = new Vue({ el: '#demo', data: { text: "hello world" } }) setTimeout(function(){ = "hello new world" }, 1000) <body> <div > <div v-text="text"></div> </div> </body>
The above is the entire idea of the entire vue data driver part. If you want to have a more detailed understanding of the implementation, it is recommended to look at the code in vue in depth.
The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.