Vue原理之模板編譯

2021-09-24 06:37:35 字數 3193 閱讀 8930

// 模板內容

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...