Vue uses the https://jsrun.net/RMIKp/embedded/all/light The MVVM framework mainly includes two aspects: updating the view when the data changes, and updating the data when the view changes. The view changes and updates the data. If it is a tag like input, you can use To update the view when data changes, you can use the 1. Implementation process Now that we know how to implement two-way binding, we must first hijack and monitor the data, so we need to set up an If the property changes, the subscriber A directive parser So the process is probably like this:
2. Display an Observer var library = { book1: { name: "", }, book2: "", }; observe(library); library.book1.name = "vue authoritative guide"; // The property name has been monitored, and the current value is: "vue authoritative guide" library.book2 = "No such book"; // The attribute book2 has been monitored, and the current value is: "No such book" // Add detection function for data defineReactive(data, key, val) { observe(val); // Recursively traverse all sub-attributes let dep = new Dep(); // Create a new dep Object.defineProperty(data, key, { enumerable: true, configurable: true, get: function() { if (Dep.target) { // Determine whether to add a subscriber. This is only necessary for the first time, and not for the next time. For details, see the Watcher function dep.addSub(Dep.target); // Add a subscriber } return val; }, set: function(newVal) { if (val == newVal) return; // return if the value has not changed val = newVal; console.log( "Property" + key + " has been monitored, and the current value is: "" + newVal.toString() + """ ); dep.notify(); // If the data changes, notify all subscribers. }, }); } // All properties of the monitoring object function observe(data) { if (!data || typeof data !== "object") { return; // If it is not an object, return } Object.keys(data).forEach(function(key) { defineReactive(data, key, data[key]); }); } // Dep is responsible for collecting subscribers and triggering the update function when the property changes. function Dep() { this.subs = {}; } Dep.prototype = { addSub: function(sub) { this.subs.push(sub); }, notify: function() { this.subs.forEach((sub) => sub.update()); }, }; In the idea analysis, there needs to be a subscriber Dep that can accommodate subscriber messages, which is used to collect subscribers and execute the corresponding update function when the attributes change. From the code, adding the subscriber Dep in In So far, a relatively complete 3. Implement Watcher The subscriber So how do you trigger get? Because we have already set We only need to cache the subscriber on Dep.target when the subscriber Watcher is initialized, and remove it after adding it successfully. function Watcher(vm, exp, cb) { this.cb = cb; this.vm = vm; this.exp = exp; this.value = this.get(); // Add yourself to the subscriber's operation} Watcher.prototype = { update: function() { this.run(); }, run: function() { var value = this.vm.data[this.exp]; var oldVal = this.value; if (value !== oldVal) { this.value = value; this.cb.call(this.vm, value, oldVal); } }, get: function() { Dep.target = this; // Cache itself to determine whether to add a watcher. var value = this.vm.data[this.exp]; // Force execution of the get function in the listener Dep.target = null; // Release yourself return value; }, }; So far, the simple Because the parser Convert the code to ES6 constructor and preview it. https://jsrun.net/8SIKp/embed... Because this code does not implement a compiler but directly passes in the bound variables, we only set a data ( And make the changes after two seconds. You can see that the page has also changed. // MyVue proxyKeys(key) { var self = this; Object.defineProperty(this, key, { enumerable: false, configurable: true, get: function proxyGetter() { return self.data[key]; }, set: function proxySetter(newVal) { self.data[key] = newVal; } }); } The purpose of the above code is to proxy the key of 4. Implement CompileAlthough two-way data binding is implemented above, the DOM nodes are not parsed during the whole process, but are fixedly replaced. Therefore, a parser is required to parse and bind the data. Implementation steps of parser
In order to parse the template, you first need to parse the DOM data, and then process the corresponding instructions on the DOM elements. Therefore, the entire DOM operation is relatively frequent. You can create a new fragment and store the required parsed function nodeToFragment(el) { var fragment = document.createDocumentFragment(); var child = el.firstChild; while (child) { // Move the Dom element into the fragment fragment.appendChild(child); child = el.firstChild; } return fragment; } Next, you need to traverse each node and perform special processing on the nodes containing relevant instructions and template syntax. First, perform the simplest template syntax processing and use regular expression to parse the syntax in the form of "{{variable}}". function compileElement (el) { var childNodes = el.childNodes; var self = this; [].slice.call(childNodes).forEach(function(node) { var reg = /\{\{(.*)\}\}/; // matches {{xx}} var text = node.textContent; if (self.isTextNode(node) && reg.test(text)) { // Determine whether it is an instruction of this form {{}} self.compileText(node, reg.exec(text)[1]); } if (node.childNodes && node.childNodes.length) { self.compileElement(node); //Continue to recursively traverse child nodes} }); }, function compileText (node, exp) { var self = this; var initText = this.vm[exp]; updateText(node, initText); // Initialize the initialized data into the view new Watcher(this.vm, exp, function (value) { // Generate a subscriber and bind the update function self.updateText(node, value); }); }, function updateText (node, value) { node.textContent = typeof value == 'undefined' ? '' : value; } After getting the outermost node, call Then you need to generate a corresponding update function subscriber for the current parameters to update the corresponding DOM when the data changes. This completes the three processes of parsing, initialization, and compilation. Next, modify myVue to use template variables for two-way data binding. https://jsrun.net/K4IKp/embed... 5. Add parsing events After adding Add a v-model and v-on parsing: function compile(node) { var nodeAttrs = node.attributes; var self = this; Array.prototype.forEach.call(nodeAttrs, function(attr) { var attrName = attr.name; if (isDirective(attrName)) { var exp = attr.value; var dir = attrName.substring(2); if (isEventDirective(dir)) { // Event instruction self.compileEvent(node, self.vm, exp, dir); } else { // v-model directive self.compileModel(node, self.vm, exp, dir); } node.removeAttribute(attrName); // Parsing completed, remove attribute} }); } // v-directive parsing function isDirective(attr) { return attr.indexOf("v-") == 0; } // on: directive parsing function isEventDirective(dir) { return dir.indexOf("on:") === 0; } The 6. Full version of myVue Add a class MyVue { constructor(options) { var self = this; this.data = options.data; this.methods = options.methods; Object.keys(this.data).forEach(function(key) { self.proxyKeys(key); }); observe(this.data); new Compile(options.el, this); options.mounted.call(this); //Execute the mounted function after everything is done} proxyKeys(key) { // Proxy this.data property to this var self = this; Object.defineProperty(this, key, { enumerable: false, configurable: true, get: function getter() { return self.data[key]; }, set: function setter(newVal) { self.data[key] = newVal; }, }); } } Then you can test it. https://jsrun.net/Y4IKp/embed... Let’s summarize the process. If you look back at this diagram, it will be much clearer now. You can view the code address: Vue2.x two-way binding principle and implementation This is the end of this article about the two-way binding principle and implementation of You may also be interested in:
|
<<: Analysis of the Principles of MySQL Slow Query Related Parameters
>>: A brief discussion on MySQL large table optimization solution
Code: Copy code The code is as follows: <!DOCTY...
As shown below: #!/usr/bin/env python3.5 import p...
When using MySQL, we often sort and query a field...
Table of contents Pull a centos image Generate ng...
nginx installation Ensure that the virtual machin...
Responsive layout systems are already very common...
Jellyka BeesAntique Handwriting [ank]* Jellyka Cut...
Let’s take a look at a chestnut first EXPLAIN sel...
When switching users in the docker container, it ...
Table of contents Preface use Component Writing D...
A problem occurred when configuring a cluster. Or...
Hexo binds a custom domain name to GitHub under W...
A design soldier asked: "Can I just do pure ...
Achieve results Implementation ideas The melting ...
Looking at a website is actually like evaluating a...