// 模板內容
type="text"
v-model="message">
} }div>
div>
// vue指令碼
let vm = new vue(
}})複製**看到上面的**,使用過vue的同學能知道頁面的渲染結果會如下圖所示:
那他是如何進行渲染的呢,我們帶著問題來進入正題。
class
vue }
}複製**
以上**就是對new vue時傳遞的引數el和data進行儲存,再利用compile來對編譯模板。
新建乙個compile.js的檔案,並建立compile類
class
compile
}this.compile(fragment);
// 把編譯完成的元素放到頁面中}}}
複製**
由於vue中的el是可以傳遞選擇器和元素節點的,我們這裡也對el做了相應的處理。
判斷使用者傳遞的el是否是元素節點,如果是元素節點使用,如果是選擇器,就獲取元素後進行使用。
// iselememtnode
iselememtnode(node)
複製**
node2fragment(el)
return fragment;
}複製**
這樣我們就得到了fragment,接下來的處理,我們只需要對fragment進行處理即可。
compile(fragment) else
})}複製**
獲取所有子元素後,分別針對是元素節點和文字節點的情況進行處理,需要指出的一點就是,元素節點內部可能還有子元素, 所以我們以當前子節點為引數遞迴執行compile。
我們再分別來看一下compileelement和compiletext兩個方法
// 編譯文字節點
compiletext(node) }並且中間不存在}的值
let reg = /\]+)\}\}/g;
if (reg.test(expr))
}複製**
其中用到的正則:
/\]+)\}\}/g;
複製**
如果對這個正則不理解,我們可以配合圖來理解一下
他實現的功能就是匹配開頭是 } 並且中間不存在 } 的字串模板。
得到字串模板之後我們就可以vm例項中取到對應的值,具體的處理,我們分離到compileutil中來實現。
如果是元素節點,我們需要考慮的就是其存在指令的情況(本篇文章只講述v-model的情況)
我們分為三步來實現該功能
獲取元素節點的屬性集合
判斷屬性是否為指令(isdirective函式)
如果是指令,利用compileutil函式做對應處理。
// 編譯元素節點
compileelement(node)
})}// 如果是v-開頭,我們就認為他是指令
isdirective(name)
複製**
以上compiletext和compileelement兩個方法中,具體的處理方式都使用到了compileutil這個輔助類,我們可以來看一下其**實現。
我們先來看對於text的處理。
經過以上的處理,我們會拿到類似於}的字串,有了這個字串,我們還需要下面幾步:
得到}中的***
尋找vm.$data中***對應的值
得到對應值後,更新對應節點的文字內容
上面需要處理的乙個難點是:我們的需要的值可能是物件中的物件,類似於},解決方案為:先把字串分隔成陣列,再使用reduce每次都取到下乙個key,最後利用key取到對應物件的值。
// 編譯所需的輔助方法
compileutil = , vm.$data);
},gettextval(expr, vm) ]+)\}\}/g, (...arguments) => }
// arguments[1]是***
return
this.getval(vm, arguments[1]);
});},
text(node, vm, expr) ,
updater:
}}複製**
處理完了text,再來看如何處理指令在上面的compileelement方法中,我們判斷了節點屬性是否是指令,如果是指令我們就拿到具體的指令,例如v-model我們就拿到model,到這裡,我們還需要以下幾步:
獲取到指令所對應的key,例如v-model=「message"中的message
更新節點的value值為vm.
設定節點的value值為對應的值
為了實現以上需求,我們給compileutil新增model方法
model(node, vm ,expr) ,
複製**
對應的modelupdater:
modelupdater(node, value)
複製**
完整的compileutil**如下
// 編譯所需的輔助方法
compileutil = , vm.$data);
},gettextval(expr, vm) ]+)\}\}/g, (...arguments) => );
},text(node, vm, expr) ,
model(node, vm ,expr) ,
updater: ,
modelupdater(node, value)
}}複製**
到這裡,文字節點和v-model指令的編譯都已經完成。
複製**
到這裡,乙個基礎的編譯環節就宣告完成,開啟頁面就能得到期待的渲染結果了???
斗膽發文,歡迎吐槽和指正。
附上完整**示例,期待與您共同進步:github.com/ljhhhhhh/mv…
Vue模板編譯原理
將模板字串轉成element ast 通過正則去匹配生成乙個 ast 樹 例如 生成對應的ast children attrslist attrsmap children static false,expression s name 通過正則去匹配起始標籤生成對應的tag等資訊 通過乙個棧記錄乙個層...
Vue原理 十三 模板編譯
模板是什麼?模板不是html,有指令,插值 js表示式,能判斷 迴圈 html是標籤語言,只有js才能實現判斷 迴圈 圖靈完備的 因此,模板一定是轉換為某種js 即編譯模板 模板編譯在元件渲染過程中的作用 1 前置知識 with語法 const obj console.log obj.a 100 c...
vue模板編譯
vue 的模板編譯是在 mount的過程中進行的,在 mount 的時候執行了compile 方法來將 template 裡的內容轉換成真正的 html complie 最終生成 render 函式字串,等待呼叫。這個方法分為三步 parse解析 ast 的全稱是 abstract syntax t...