In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/01 Report--
This article mainly introduces the relevant knowledge of vue two-way binding principle case analysis, the content is detailed and easy to understand, the operation is simple and fast, and has a certain reference value. I believe you will gain something after reading this vue two-way binding principle example analysis article. Let's take a look at it.
Customize the vue class
Vue requires at least two parameters: template and data.
Create a Compiler object, render the data to the template, and mount it to the specified follower node.
Class MyVue {/ / 1, receives two parameters: template (root node), and data object constructor (options) {/ / save template, and data object if (this.isElement (options.el)) {this.$el = options.el;} else {this.$el = document.querySelector (options.el);} this.$data = options.data; / / 2. According to the template and the data object, render to the root node if (this.$el) {/ / listen on the get/set new Observer (this.$data) of all attributes of data; new Compiler (this)}} / / determine whether it is a dom element isElement (node) {return node.nodeType = 1;}} to render the data to the page for the first time
Compiler
1Partition node2fragment function extracts template elements into memory to facilitate rendering the data to the template, and then mounting it to the page at one time
2. After the template is extracted to memory, use the buildTemplate function to traverse the template element
Element node
Use the buildElement function to check for attributes that begin with a v-on an element
Text node
Use the buildText function to check for {{}} content in the text
3. Create a CompilerUtil class to process the vue instruction and {{}} to complete the rendering of the data
4, this completes the first data rendering, and then automatically updates the view when the data needs to be changed.
Class Compiler {constructor (vm) {this.vm = vm; / / 1. Put the elements on the web page into memory let fragment = this.node2fragment (this.vm.$el); / / 2. Compile the in-memory element this.buildTemplate (fragment) with the specified data; / / 3. Re-render the compiled content to this.vm.$el.appendChild (fragment) on the web page;} node2fragment (app) {/ / 1. Create an empty document fragment object let fragment = document.createDocumentFragment (); / / 2. Compilation cycle takes each element let node = app.firstChild; while (node) {/ / Note: as long as the element is added to the document fragment object, the element will automatically disappear from the web page fragment.appendChild (node); node = app.firstChild;} / / 3. Returns the document fragment object return fragment;} buildTemplate (fragment) {let nodeList = [... fragment.childNodes]; nodeList.forEach (node = > {/ / needs to determine whether the node currently traversed is an element or a text if (this.vm.isElement (node)) {/ / element node this.buildElement (node)) / / processing child elements this.buildTemplate (node);} else {/ / text node this.buildText (node);}} buildElement (node) {let attrs = [... node.attributes]; attrs.forEach (attr = > {/ / v name model = > {name:v-model value:name} let {name, value} = attr / / v-model / v-html / v-text / v-xxx if (name.startsWith ('v v-xxx if')) {/ / v-model-> [v, model] let [_, directive] = name.split ('-'); CompilerUtil [directive] (node, value, this.vm);}} buildText (node) {let content = node.textContent Let reg = /\ {{. +?\}\} / gi; if (reg.test (content)) {CompilerUtil ['content'] (node, content, this.vm);} let CompilerUtil = {getValue (vm, value) {/ / parse the attribute this.data.aaa.bbb.ccc return value.split ('.'). Reduce ((data, currentKey) = > {return data [currentKey.trim ()] }, vm.$data);}, getContent (vm, value) {/ / parse the variable let reg = /\ {(. +?)\} in {{}} / gi; let val = value.replace (reg, (... args) = > {return this.getValue (vm, args [1]);}); return val }, / / parse the v-model instruction model: function (node, value, vm) {/ / create a Wather for dom and assign new Watcher (vm, value, (newValue, oldValue) = > {node.value = newValue;}) to Watcher.target before triggering getter; let val = this.getValue (vm, value); node.value = val }, / / parse v-html directive html: function (node, value, vm) {/ / create Wather for dom before triggering getter, and assign new Watcher (vm, value, (newValue, oldValue) = > {node [XSS _ clean] = newValue;}) to Watcher.target; let val = this.getValue (vm, value); node [XSS _ clean] = val }, / / parse the v-text instruction text: function (node, value, vm) {/ / create a Wather for dom and assign new Watcher (vm, value, (newValue, oldValue) = > {node.innerText = newValue;}) to Watcher.target before triggering getter; let val = this.getValue (vm, value); node.innerText = val }, / / parse the variable content in {{}}: function (node, value, vm) {let reg = /\ {(. +?)\}\} / gi Let val = value.replace (reg, (... args) = > {/ / before triggering getter, create a Wather for dom and assign new Watcher (vm, args [1], (newValue, oldValue) = > {node.textContent = this.getContent (vm, value);}); return this.getValue (vm, args [1]);}); node.textContent = val;} to implement a data-driven view
Observer
1. Use the defineRecative function to Object.defineProperty the data, so that every data in the data can be monitored by get/set
2. Next, we will consider how to update the view content after listening for a change in the value of data. Use the Observer design pattern to create Dep and Wather classes.
Class Observer {constructor (data) {this.observer (data) } observer (obj) {if (obj & & typeof obj = 'object') {/ / traversal fetches all the attributes of the incoming object, adding the get/set method for (let key in obj) {this.defineRecative (obj, key) to all the attributes traversed Obj [key])} / / obj: object to be operated / / attr: need to add property of get/set method / / value: need to add value of property of get/set method defineRecative (obj, attr, value) {/ / if the value of attribute is another object, then you also need to add get/set method this.observer (value) to all properties of this object. / / step 3: put all the observer objects of the current attribute into the publish / subscribe object of the current property to manage let dep = new Dep (); / / create the publish / subscribe object Object.defineProperty (obj, attr, {get ()) {/ / collect dependencies Dep.target & & dep.addSub (Dep.target); return value here }, set: (newValue) = > {if (value! = = newValue) {/ / if the new value assigned to the property is another object, you also need to add the get/set method this.observer (newValue) to all properties of this object; value = newValue; dep.notify (); console.log ('listen for changes in data') })}
Create Dep and Wather classes using the Observer design pattern
1. The purpose of using the Observer Design pattern is:
Parse the template and collect the collection of dom nodes in which some data in the data is used in the template. When the data changes, updating the dom node set realizes the data update.
Dep: used to collect a collection of dom nodes that a data attribute depends on and provide update methods
Watcher: the wrapper object for each dom node
Attr: the data attribute used by this dom
Cb: a callback function that modifies the doms value, which will be received when created
2. I feel that there is no problem with the train of thought here, and the victory is at hand. So how do you use Dep and Watcher?
Add a dep for each attribute to collect dependent dom
Because the data data is read when the page is rendered for the first time, and the getter of the data is triggered, the dom is collected here
How to collect it? when the CompilerUtil class parses commands such as v-model and {{}}, getter will be triggered. Before triggering, we create Wather, add a static attribute to Watcher, point to the dom, and then get the static variable in the getter function and add it to the dependency to complete the collection. Because the static variable is assigned before each getter is triggered, there is no case of collecting incorrect dependencies.
Class Dep {constructor () {/ / this array is the this.subs = [];} / subscription observation method addSub (watcher) {this.subs.push (watcher);} / publish subscription method notify () {this.subs.forEach (watcher = > watcher.update ()) }} class Watcher {constructor (vm, attr, cb) {this.vm = vm; this.attr = attr; this.cb = cb; / / get the current old value this.oldValue = this.getOldValue () when creating the observer object;} getOldValue () {Dep.target = this; let oldValue = CompilerUtil.getValue (this.vm, this.attr); Dep.target = null; return oldValue } / / define an updated method to determine whether the new and old values are the same update () {let newValue = CompilerUtil.getValue (this.vm, this.attr); if (this.oldValue! = = newValue) {this.cb (newValue, this.oldValue);}
3. When the data binding is implemented here, the view is updated automatically. I originally wanted the code to be implemented step by step, but found it difficult to handle, so I posted the complete class.
Implement view-driven data
In fact, it is listening for the input and change events of the input box. Modify the model method of CompilerUtil. The specific code is as follows
Model: function (node, value, vm) {new Watcher (vm, value, (newValue, oldValue) = > {node.value = newValue;}); let val = this.getValue (vm, value); node.value = val; / / look here node.addEventListener ('input', (e) = > {let newValue = e.target.value; this.setValue (vm, value, newValue);})}, summary
Principle of two-way binding of vue
Vue receives a template and a data parameter.
1. First, we recursively traverse the data in data, execute Object.defineProperty for each attribute, and define get and set functions. And add a dep array for each attribute. When the get executes, a watcher is created for the called dom node to store in the array. When the set is executed, the value is reassigned and the notify method of the dep array is called, notifying all that the property watcher is used, and updating the contents of the corresponding dom.
2. If the template is loaded into memory and the element in the recursive template is detected with a command starting with v-or an instruction with double curly braces, it will take the corresponding value from data to modify the content of the template. At this time, the dom element will be added to the dep array of the attribute. This implements the data-driven view. When processing the v-model instruction, the input event (or change) is added to the dom, and the value of the corresponding attribute is modified as input, thus realizing the page-driven data.
3. After binding the template to the data, add the template to the real dom tree.
How do I put watcher in the dep array?
When parsing the template, the corresponding data attribute value will be obtained according to the v-instruction. At this time, the get method of the attribute will be called. We first create a Watcher instance and obtain the attribute value inside it, which is stored in the watcher as the old value. Before we get this value, we add the attribute Watcher.target = this; to the Watcher prototype object and then take the value, which we will say Watcher.target = null. In this way, get can get the watcher instance object according to Watcher.target when it is called.
The principle of methods
When creating a vue instance, receive the methods parameter
Encountered the instruction of v-on while parsing the template. The listener for the corresponding event is added to the dom element, and the vue is bound to the this:vm.$ methods [value] .call (vm, e) of the method using the call method.
The principle of computed
When creating a vue instance, receive the computed parameter
When initializing the vue instance, perform Object.defineProperty processing for the key of the computed and add the get attribute.
This is the end of the article on "example Analysis of the principle of vue two-way binding". Thank you for reading! I believe you all have a certain understanding of the knowledge of "case analysis of vue two-way binding principle". If you want to learn more, you are welcome to follow the industry information channel.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.