vue2.5.13思想

以下所有代碼都是根據源碼思想的簡化簡寫偽碼。

  • 1.將template解析為AST(Abstract Syntax Tree)

    /**
     * 將template解析為ast
     * <div class="parent">{{tips}}</div>
     * 解析為ast(以對象的形式標識dom)后:
     * {
     *     attrsMap:{class:"parent"},//屬性集合
     *     children:[{
     *          expression:"_s(tips)",//render方法表達式
     *          static:false,//是否是靜態節點
     *          text:"{{tips}}",//文本內容
     *          type:2//2:占位符文本
     *     }],//子節點集合
     *     tag:'div',//標簽名
     *     type:1,//節點類型 1:ele  2:占位符文本  3:純文本
     *     staticClass:'parent',//靜態類
     *     static:false,//是否是靜態節點
     *     parent:null//父AST對象
     * }
     */
    var ast = parse(template.trim(),options);
    // 至于template解析為ast的流程,也就是parse的實現。是根據正則匹配出標簽開始,匹配出標簽結束,匹配出標簽屬性,匹配出標簽文本。
    // 再通過先后觸發的標簽開始結束方法確定父子關系。這里主要記錄思想,實現不過多贅述,詳細可看parse的源碼
    
  • 2.將AST編譯為render方法字串

    /**
     * 將AST編譯為render方法
     * {
     *     attrsMap:{class:"parent"},//屬性集合
     *     children:[{
     *          expression:"_s(tips)",//render方法表達式
     *          static:false,//是否是靜態節點
     *          text:"{{tips}}",//文本內容
     *          type:2//2:占位符文本
     *     }],//子節點集合
     *     tag:'div',//標簽名
     *     type:1,//節點類型 1:ele  2:占位符文本  3:純文本
     *     staticClass:'parent',//靜態類
     *     static:false,//是否是靜態節點
     *     parent:null//父AST對象
     * }
     * 編譯為render方法字串后,!!!這里是字串不是方法
     * with (this) {
     *     return _c('div', {staticClass: "parent"}, [_v(_s(tips))])
     * }
     * 返回值code.render方法中就是這個字串,具體的_c,_v,_s等等方法之后介紹
     * 到此AST的使命就結束了,那么render方法的作用是啥呢?其實執行render方法得到的就是template對應的虛擬dom(vnode)
     */
    var code = generate(ast,options);
    
  • 3.到此template就被解析成了render方法,小節一波

    /**
     * 靜態節點:永遠不會因為數據改變而變化的節點
     * 1.vue被實例化
     * 2.將dom轉為template字串 
     * 3.將template字串轉為AST 
     * 4.將AST轉為render方法(staticRenderFns是靜態節點render方法的數組)
     * 5.將render方法掛載到Vue實例下的$options屬性下的render上(同原理還有staticRenderFns)
     * 
     * 
     */
    function Vue(option){
        //...
        this.$mount();
        //...
    }
    Vue.prototype.$mount = function() {
        //...
       var compiled = Vue.compile(template);
       this.$options.render = compiled.render;
       this.$options.staticRenderFns = compiled.staticRenderFns;
        //...
    }
    Vue.compile = function (template) {
        var ast = parse(template.trim(),options);
        var code = generate(ast,options);
        var res = {};
        res.render = createFunction(code.render, fnGenErrors);
        res.staticRenderFns = code.staticRenderFns.map(function (code) {
           return createFunction(code, fnGenErrors)
        });
        return res;
    }
    
  • 4.現在render方法已經綁定到實例中,接下來處理數據給數據添加攔截方法

    /**
     * 添加數據攔截,先說Object.defineProperty
     */
    
    var data = {
        
    }
    
    function Vue(option){
        //...
        this.$mount();
        //...
    }
    Vue.prototype.$mount = function() {
        //...
       var compiled = Vue.compile(template);
       this.$options.render = compiled.render;
       this.$options.staticRenderFns = compiled.staticRenderFns;
        //...
    }
    Vue.compile = function (template) {
        var ast = parse(template.trim(),options);
        var code = generate(ast,options);
        var res = {};
        res.render = createFunction(code.render, fnGenErrors);
        res.staticRenderFns = code.staticRenderFns.map(function (code) {
           return createFunction(code, fnGenErrors)
        });
        return res;
    }
    

_m方法 靜態根節點

_l方法 for循環

_e方法 if語句

_c方法 處理完指令剩余標簽

_v方法 處理文本節點或含mustache的文本

with方法的作用:(來實現scope)
with(obj)作用就是將后面的{}中的語句塊中的缺省對象設置為obj,那么在其后面的{}語句塊中引用obj的方法或屬性時可以省略obj.的輸入而直接使用方法或屬性的名稱。

```javascript
function scope() {
    this.data = {
        test1: '獨立作用域'
    };
    this.say = function (ss) {
        console.log(ss);
    }
}

var s = new scope();
var fncode = 'with(this){say(data.test1);}';
var render = new Function(fncode);
render.call(s, s);
```

未完待續!!!!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。