Preliminary Understanding and Understanding of vue Source Code

Posted by edcellgavin on Sat, 22 Jun 2019 21:38:02 +0200

According to the introduction of vue's official website, we can know that Vue is a mvvm framework and is responsive. In order to further understand its connotation, I realized a simple demo of mvvm learning. Below to share with you, welcome to discuss together.

1. The minimum content of mvvm

  1. Instruction sets, such as text, model, etc.
  2. Data model, data that interacts with views
  3. Component support: dynamic updates of some html code

II. My Realization

1. Definition of Variable and Realization of watch

var directives = {}; //Instruction set
var vNodes = new Array(); //Analytical Dom aggregate

var dataModel = {
    name:"name",
    title: "title"
}; //data Model

var Watch = {
    isInit: false,
    watchs: new Array(),
    run: function(newValue, expOrfn){ 
        var self = this;
        if(!self.isInit){
            expOrfn.call(vModel);
        }
        this.watchs.map(function(data,index){
            data.nodes.map(function(d,i){
                if(self.isInit){
                    d.directive.init(newValue, d, data); //Bind initialization values and initialize some events
                }else{
                    d.directive.update(newValue, d, data); //Only update the value, at this time run Call value value-set
                }
            });
        });
        
        self.watchs = [];
    },
    push:function(watch){
        this.watchs.push(watch);
    }
} //task management

Explain:

  1. The push method of Watch is used to add dependencies, and then run to execute so dependencies. When execution is complete, the collection of current dependencies needs to be cleaned up. The collection of dependencies in vue is done in dep, while task management provided by watch (do not know if the understanding is correct)

2. Definition of instructions

directives.text = { 
    init: function(value, vNode){
        vNode.elm.textContent = value;
    },
    update: function(value, vNode){
        vNode.elm.textContent = value;
    }
}
//What to do if you need to respond to events
directives.model ={ 
    init: function(value, vNode, _watch){
        vNode.elm.value = value; //Judging what's happening to you, you shouldn't change yourself any more. 
        vNode.elm.addEventListener('keyup',function(evt){
            vNode.model[_watch.key] = vNode.elm.value;
        }); 
    },
    update:function(){

    }   
}

Explain:

  1. As an example of demo learning, only two simple text and model designations are defined, text: for data display, and model for input (input box) response.

3. Generation of vModel

//Transformation vModel,Provisional Support Level 1
var properties = Object.getOwnPropertyNames(dataModel);
var vModel = {}, formSetting = false;
for( var index in properties){ 
    (function refreshData(_index){
        var key = properties[_index];
        var property = Object.getOwnPropertyDescriptor(dataModel, key);
        var setter = property.set;
        var getter = property.get;
        var _val = property.value;
        var _getter = function(){
            var val = getter ? getter.call(vModel) : _val;
            //Collecting dependencies, and watch Separate
            Watch.push({
                key: key,
                nodes: vNodes.filter(function(data,index){
                    return data.modelKey == key ? true : false;
                }),
                getter: _getter
            });
            return val;
        };
        Object.defineProperty(vModel, key, {
            configurable: true,
            enumerable: true,
            set: function(value){
                if(setter){
                    setter.call(vModel, value);
                } 
                //Dealing with dependencies
                Watch.run(value, _getter);
                //this.value = value;
            },
            get: _getter

        })
    })(index);
}

Explain:

  1. vModel is generated based on dataModel, that is to say, the get and set methods of each attribute are customized. It can also be implemented with proxy in es6 (right or wrong).
  2. When the attribute set is set, the get method is called first to collect the dependencies. When the convenience value is changed, the content affected can be modified.

4. Resolving dom to vNode

//analysis vNodes
var app = document.getElementById('app');
app.childNodes.forEach(function(data,index){
    if(data.nodeType != 1) return;
    var hv = data.getAttribute('data-hv');
    var hvs = hv.split(',');
    hvs.forEach(function(item,row){
        var keyValue = item.split(':'); //vNode There must be something on the object. model,This is convenient. vNode Search for the appropriate time vModel
        vNodes.push({
            directive: directives[keyValue[0]],
            modelKey: keyValue[1],
            model: vModel,
            elm: data
        });
    });
});

Explain:

  1. It is far-fetched to parse vNode here because it only collects the instructions specified by data-hv on dom and stores the instructions, elements, vModel and other components into an object in vNodes for reference when the get method of vModel attributes collects dependencies.

5. First initialization

//Call all get Once
Watch.isInit = true;
var _keys = Object.getOwnPropertyNames(vModel);
_keys.map(function(key,data){
    var data = vModel[key];
    Watch.run(data); 
});
Watch.isInit = false;

Explain:

  1. Render the value of the initialized vModel to Dom, where each get is actively executed, and then run the watch.run method.
  2. Here, the design and implementation of my own feelings and the idea of vue is not right, if you see the superior, please point out and guide.

6. parsed dom

<div id="app">
    <span data-hv="text:title"></span>
    <span data-hv="text:title"></span>
    <input data-hv="model:title" />
</div>

Topics: Javascript Vue Attribute