Vue. Js responsive principle

In vue.js, when we modify the data, the view updates with it. This is the two-way data binding (also known as the reactive principle) of vue.js.

Core: Observer pattern and object.defineProperty () method.

In VUE, there is a Watcher instance for each component instance, which records data properties “touched” during component rendering as Collect as Dependency. Watcher is then notified (Notify process) when the setter for the dependency fires, causing its associated component to re-render (Trigger re-render process) — observer mode.

Ii. Components

1. What is MVVM

MVVM is called model-view-viewModel, which consists of View, ViewModel and Model. The View layer represents the View layer (UI). The Model layer represents the data, and the ViewModel layer connects the Model to the View. Two-way data binding: Data affects views, and views affect data.

2. Components

  • Observer: Implements responsive objects by converting ordinary data into responsive data.
  • Dep (Subscriber, dependent collector) : Add an observer primarily through addSub(), notify the observer through notify(), and call the observer’s Update to update the corresponding view.
  • Watcher (observer) : The observer’s get() method gets the value before it is updated, and when the data is updated, the observer’s UPDATE is called to update the corresponding view.

3. MVVM implementation

In different frameworks, the principle of MVVM implementation is different; In VUE, the data hijacking + publish subscribe model is used.

  • 2.1 Data hijacking observe

Define all attributes with Object.defineProperty. That is, when you pass an ordinary JavaScript object into a Vue instance as the data option, Vue iterates through all of the object’s properties, And use Object.defineProperty to turn all of these properties into getters/setters (reactive forms of data).

Data function Observe(data){for(let key in data){let val=data[key] Observe(val) object.defineProperty (data,key,{ enumerable:true, get(){ return val }, Set (newVal){if(newVal==val) return val=newVal observe(newVal)}})}} // Monitor data function observe(data){if(typeof data! ='object') return return new Observe(data) }Copy the code

By hijacking the data (Model), when the data changes, the data triggers the methods bound at the time of hijacking to update the view.

Data broker:

function myVue(options={}){ this.$options=options var data=this._data=this.$options.data observe(data) // This proxy this._data for(let key in data){object.defineProperty (this,key,{enumerable:true, get(){ return this._data[key] }, set(newVal){ this._data[key]=newVal } }) } }Copy the code
  • 2.2 Publish and subscribe model

Subscribe (store), publish (execute).

Subscribers add observers primarily through the addSub() method, notify them through notify(), and call the observer’s Update to update the corresponding view. The Watcher’s get() method gets the unupdated value, creates a publish/subscribe function for each property, and calls the observer’s UPDATE to update the corresponding view when the data is updated.

  • 2.3. Compile template

Using the method of virtual DOM, the content in EL is first moved into memory by creating document fragments, and then it is searched and replaced in memory. (The content of text nodes with double braces in the page and the content bound by v-model are searched and replaced with the data in data.) , and finally remount the results back to the page.

Get the template template ast syntax tree — render function — virtual DOM — real DOM

Function Compile(el,vm){// el indicates the range vm.$el=document.querySelector(el) let fragment=document.createDocumentFragment(); While (child=vm.$el.firstChild){fragment.appendChild(child)} replace(fragment) function replace(fragment){ Array.from(fragment.childNodes).forEach((node)=>{ console.log("node",node); Let the text = node. TextContent let reg = / \ {\ {(. *) \} \} / / / if a text node (the node. The nodeType = = 3 && reg. Test (text)) { Console. log(" text node ",RegExp.$1); //this.a.a this.b let arr=RegExp.$1.split('.')// ['a','a'] ['b'] let val=vm arr.forEach((key)=>{ val=val[key] }) Node.textcontent =text.replace(reg,val)} if(node.childNodes){replace(node)}})} // Remount the document fragment on the page vm.$el.appendChild(fragment) }Copy the code

Reference: juejin. Cn/post / 691627…

Mp.weixin.qq.com/s/yCdRsJ09Q…