首頁  >  文章  >  web前端  >  一起學習理解vue源碼

一起學習理解vue源碼

零下一度
零下一度原創
2017-06-26 09:50:481400瀏覽

      根據vue的官網介紹,可以得知vue是mvvm框架,且是響應式的。為了更深入了理解其內涵,本人以及理解實現了一個簡單的mvvm學習的demo。以下分享給大家,歡迎大家一起討論。

一、mvvm至少包含的內容

  1. 指令集合,如:text、model等

  2. 資料模型,與視圖互動的資料

  3. 元件的支援:也就是部分html程式碼的動態更新

二、我的實作

#1. 變數的定義與watch的實作

var directives = {}; //指令集合var vNodes = new Array(); //解析的Dom集合var dataModel = {
    name:"name",
    title: "title"}; //数据Modelvar 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); //绑定初始化值, 以及初始化一些事件}else{
                    d.directive.update(newValue, d, data); //只更新值,此时run的调用来值value-set                }
            });
        });
        
        self.watchs = [];
    },
    push:function(watch){this.watchs.push(watch);
    }
} //任务管理

說明:

  1. Watch的push方法,用於依賴的添加,然後run來執行所以依賴,執行完成後,需要清理當前依賴的集合。在vue中依賴的收集是在dep中完成的,而watch提供的任務管理(不知道理解是否正確)

2. 指令的定義

directives.text = { 
    init: function(value, vNode){
        vNode.elm.textContent = value;
    },
    update: function(value, vNode){
        vNode.elm.textContent = value;
    }
}//需要响应事件的怎么办directives.model ={ 
    init: function(value, vNode, _watch){
        vNode.elm.value = value; //判断自己发生的改变,不应该再改变自己 vNode.elm.addEventListener('keyup',function(evt){
            vNode.model[_watch.key] = vNode.elm.value;
        }); 
    },
    update:function(){

    }   
}

說明:

  1. #由於是demo學習範例,所以只定義了簡單的text和model兩個指定,text:用於資料的顯示,而model用於input(輸入框)的回應

3. vModel的產生

//转换vModel,暂支持一级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;//收集依赖,与watch要分开            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);
                } //处理依赖                Watch.run(value, _getter);//this.value = value;            },
            get: _getter

        })
    })(index);
}

說明:

  1. vModel是根據dataModel產生的,也就是自訂了每個屬性的get和set方法,在es6中也可以用proxy實作(是否說對了)。

  2. 在屬性set的時候,會先呼叫get方法來收集依賴。方便值改變後,能將所影響的內容都修改掉。

4. 解析dom為vNode

//解析vNodesvar 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对象上一定要有model,这是方便vNode相应时候的找vModel        vNodes.push({
            directive: directives[keyValue[0]],
            modelKey: keyValue[1],
            model: vModel,
            elm: data
        });
    });
});

說明:

  1. 這裡說解析為vNode很牽強,因為此只是收集了dom上data-hv指定的指令,並將對就的指令、元素、vModel等組成一個物件儲存在vNodes中,以供vModel各屬性的get方法收集依賴時引用。

5. 第一次初始化

//调用所有的get一次Watch.isInit = true;var _keys = Object.getOwnPropertyNames(vModel);
_keys.map(function(key,data){var data = vModel[key];
    Watch.run(data); 
});
Watch.isInit = false;

#說明:

  1. 將初始化的vModel的值渲染到Dom上,這裡是主動執行每個的get,然後執行watch.run方法。

  2. 此處設計與實現本人感覺與vue的思路不對,如有高人看見,麻煩提點與指引。

6. 被解析的dom

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

以上是一起學習理解vue源碼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn