摘要:源碼解析這邊解析的是從樹轉換成函數部分的源碼,由于第一次提交的源碼這部分不全,故做了部分更新,代碼全在文件夾中。入口整個語法樹轉函數的起點是文件中的函數明顯看到,函數傳入參數為語法樹,內部調用函數開始解析根節點容器節點。
開始通過對 Vue2.0 源碼閱讀,想寫一寫自己的理解,能力有限故從尤大佬2016.4.11第一次提交開始讀,準備陸續寫:
模版字符串轉AST語法樹
AST語法樹轉render函數
Vue雙向綁定原理
Vue虛擬dom比較原理
其中包含自己的理解和源碼的分析,盡量通俗易懂!由于是2.0的最早提交,所以和最新版本有很多差異、bug,后續將陸續補充,敬請諒解!包含中文注釋的Vue源碼已上傳...
今天要說的代碼全在codegen文件夾中,在說實現原理前,還是先看個簡單的例子!
{{msg}}
上述類名為container的元素節點包含5個子節點(其中3個是換行文本節點),轉化成的AST語法樹:
AST語法樹轉的render函數長這樣:
function _render() { with (this) { return __h__( "div", {staticClass: "container"}, [ " ", __h__("span", {}, [String((msg))]), " ", __h__("button", {class: {active: isActive},on:{"click":handle}}, ["change msg"]), " " ] ) }; }
可以的看出,render函數做的事情很簡單,就是把語法樹每個節點的指令進行解析。
看下render函數,它是由with函數包裹(為了改變作用域),要用的時候直接_render.call(vm);另外就是__h__函數,這個后面會說到,這個函數用于元素節點的解析,接收3個參數:元素節點標簽名,節點數據,子節點數據。這個函數最后返回的就是虛擬dom了,不過今天先不深究,先說如何生成這樣的render函數,主要是v-if、v-for、v-bind、v-on等指令的解析。
源碼解析這邊解析的是從AST樹轉換成render函數部分的源碼,由于vue2.0第一次提交的源碼這部分不全,故做了部分更新,代碼全在codegen文件夾中。
入口整個AST語法樹轉render函數的起點是index.js文件中的generate()函數:
export function generate (ast) { const code = genElement(ast); return new Function (`with (this) { return ${code}}`); }
明顯看到,generate()函數傳入參數為AST語法樹,內部調用genElement()函數開始解析根節點(容器節點)。genElement()函數用于解析元素節點,它接收兩個參數:AST對象和節點標識(v-for的key),最后返回形如__h__("div", {}, [])的字符串,看一下內部邏輯:
function genElement (el, key) { let exp; if (exp = getAndRemoveAttr(el, "v-for")) { // 解析v-for指令 return genFor(el, exp); } else if (exp = getAndRemoveAttr(el, "v-if")) { // 解析v-if指令 return genIf(el, exp, key); } else if (el.tag === "template") { // 解析子組件 return genChildren(el); } else { return `__h__("${el.tag}", ${genData(el, key) }, ${genChildren(el)})`; } }
genElement()函數內部依次調用getAndRemoveAttr()函數判斷了v-for、v-if標簽是否存在,若存在則刪除并返回表達式;隨后判斷節點名為template就直接進入子節點解析;以上條件都不符合就返回__h__函數字符串,該字符串將使用到屬性解析和子節點解析。
function getAndRemoveAttr (el, attr) { let val; // 如果屬性存在,則從AST對象的attrs和attrsMap移除 if (val = el.attrsMap[attr]) { el.attrsMap[attr] = null; for (let i = 0, l = el.attrs.length; i < l; i++) { if (el.attrs[i].name === attr) { el.attrs.splice(i, 1); break; } } } return val; }v-for 和 v-if 指令解析
讓我們先看看v-for的編譯:
function genFor (el, exp) { const inMatch = exp.match(/([a-zA-Z_][w]*)s+(?:in|of)s+(.*)/); if (!inMatch) { throw new Error("Invalid v-for expression: "+ exp); } const alias = inMatch[1].trim(); exp = inMatch[2].trim(); let key = getAndRemoveAttr(el, "track-by"); // 后面用 :key 代替了 track-by if (!key) { key ="undefined"; } else if (key !== "$index") { key = alias + "["" + key + ""]"; } return `(${exp}) && (${exp}).map(function (${alias}, $index) {return ${genElement(el, key)}})`; }
該函數先進行正則匹配,如"item in items",將解析出別名(item)和表達式(items),再去看看當前節點是否含:key,如果有那就作為genElement()函數的參數解析子節點。舉個
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/100476.html
摘要:源碼解析這邊解析的是從樹轉換成函數部分的源碼,由于第一次提交的源碼這部分不全,故做了部分更新,代碼全在文件夾中。入口整個語法樹轉函數的起點是文件中的函數明顯看到,函數傳入參數為語法樹,內部調用函數開始解析根節點容器節點。 通過對 Vue2.0 源碼閱讀,想寫一寫自己的理解,能力有限故從尤大佬2016.4.11第一次提交開始讀,準備陸續寫: 模版字符串轉AST語法樹 AST語法樹轉r...
摘要:通過對源碼閱讀,想寫一寫自己的理解,能力有限故從尤大佬第一次提交開始讀,準備陸續寫模版字符串轉語法樹語法樹轉函數雙向綁定原理虛擬比較原理其中包含自己的理解和源碼的分析,盡量通俗易懂由于是的最早提交,所以和最新版本有很多差異,后續將陸續補充, 通過對 Vue2.0 源碼閱讀,想寫一寫自己的理解,能力有限故從尤大佬2016.4.11第一次提交開始讀,準備陸續寫: 模版字符串轉AST語法...
摘要:通過對源碼閱讀,想寫一寫自己的理解,能力有限故從尤大佬第一次提交開始讀,準備陸續寫模版字符串轉語法樹語法樹轉函數雙向綁定原理虛擬比較原理其中包含自己的理解和源碼的分析,盡量通俗易懂由于是的最早提交,所以和最新版本有很多差異,后續將陸續補充, 通過對 Vue2.0 源碼閱讀,想寫一寫自己的理解,能力有限故從尤大佬2016.4.11第一次提交開始讀,準備陸續寫: 模版字符串轉AST語法...
閱讀 3035·2023-04-25 20:09
閱讀 3318·2021-11-23 09:51
閱讀 1971·2021-11-22 15:25
閱讀 3348·2021-11-18 10:02
閱讀 2747·2021-09-27 13:56
閱讀 1304·2019-08-30 15:44
閱讀 1149·2019-08-30 13:21
閱讀 3322·2019-08-30 11:05