1./compiler is the compiler template.
2. The /core directory is the heart of vue.js (and the focus later);
3./ Platforms is a ‘platform’ module for core modules;
4./server directory is handling server rendering;
5./ SFC directory processing file.vue;
6. The /shared directory provides global utility functions.
Vue.js is made up of core + ‘platform’ complementary code (standalone builds and runtime builds are just two options for Platforms under Platforms).
Two-way data binding for VUE
The techniques involved in bidirectional binding (reactive principle)
1. Object.defineProperty
2. Observer
3. Watcher
4. Dep
5. Directive
Copy the code
1. Object.defineProperty
var obj = {};
var a;
Object.defineProperty(obj,'a',{
get: function(){
console.log('get val');
return a;
},
set: function(newVal){
console.log('set val:'+ newVal); a = newVal; }}); obj.a // get val; <span>{{a}}</span> obj.a ='111'; // setVal :111 equals <input V-model ="a">
Copy the code
2. Observer
The observer pattern is one of the software design patterns. In this pattern, a target object manages all observer objects that depend on it and actively notifies itself when its state changes. This is usually done by calling the methods provided by each observer. This mode is commonly used in real-time event processing systems. The subscriber pattern involves three objects: publisher, topic, and subscriber. The three objects have a one-to-many relationship. Whenever the state of the topic object changes, its dependent objects are notified and automatically updated. Look at a simple example:Copy the code
- Dep
- Directive
Now that we understand the principles and architecture, let’s implement a simple VUE two-way data binding
1. Where did this Vue come from?
Observe: The core principle of bidirectional binding is Object.defineProperty
Set and get values through set and get
Bind the text property to the vue instance to use
So what’s the Dep?
Let’s see what we say in Compile again
function Compile(node, vm) {
if (node) {
this.$frag = this.nodeToFragment(node, vm);
return this.$frag;
}
}
Compile.prototype = {
nodeToFragment: function(node, vm) { var self = this; var frag = document.createDocumentFragment(); Create an HTML document fragment var child;while(child = node.firstChild) { self.compileElement(child, vm); frag.append(child); // Add all child nodes to fragment}return frag;
},
compileElement: function(node, vm) { var reg = /\{\{(.*)\}\}/; // The node type is elementif(node.nodeType === 1) { var attr = node.attributes; // Parse attributesfor (var i = 0; i < attr.length; i++) {
if (attr[i].nodeName == 'v-model') { var name = attr[i].nodeValue; Node.addeventlistener (node.adDeventListener ('input'.function(e) {// Assign the corresponding data attribute to trigger the attributesetMethod // triggersetvm[name] vm[name] = e.target.value; }); // node.value = vm[name]; // Assign data to the node new Watcher(vm, node, name,'value'); }}; } // The node type is textif (node.nodeType === 3) {
if (reg.test(node.nodeValue)) {
var name = RegExp.The $1; // Get the matching string name = name.trim(); // node.nodeValue = vm[name]; // Assign data to the node new Watcher(vm, node, name,'nodeValue'); }}}},Copy the code
Compile renders HTML. Does Watcher monitor node changes and notify Dep?
function Watcher(vm, node, name, type) { Dep.target = this; this.name = name; //text this.node = node; // this.vm = vm; // vue instance this.type =type; //nodeValue Specifies the value of the current node this.update(); Dep.target = null; } Watcher.prototype = { update:function() { this.get(); var batcher = new Batcher(); batcher.push(this); // this.node[this.type] = this.value; }, cb:function(){ this.node[this.type] = this.value; // The subscriber performs the corresponding operation}, // get the attribute value of data:function() {
this.value = this.vm[this.name]; //触发相应属性的get
}
}
Copy the code
Whoops, we were right — two-way data binding is almost done, leaving only one place for vue.nexttick ()
/** * batch constructor * @constructor */function Batcher() { this.reset(); } /** * Batch reset */ batcher.prototype.reset =function () {
this.has = {};
this.queue = [];
this.waiting = false; }; /** * add event to queue * @param job {Watcher} Watcher event */ batcher.prototype.push =function (job) {
if(! this.has[job.name]) { this.queue.push(job); this.has[job.name] = job;if(! this.waiting) { this.waiting =true;
setTimeout(() => { this.flush(); }); }}}; /** * Execute and clear the event queue */ batcher.prototype. flush =function () {
this.queue.forEach((job) => {
job.cb();
});
this.reset();
};
Copy the code
Is it super easy after watching it?
The vuE3 version will make big changes, eliminating Dep and Watcher, and binding HTML directly to data. When VUE3 comes out, write an article about VUE
Can you give me a “like” when you’re done?