Vue實(shí)現(xiàn)原理(圖文講解)(vue 實(shí)現(xiàn)原理)
本文章轉(zhuǎn)自:樂(lè)字節(jié)
文章主要講解:Vue實(shí)現(xiàn)原理
獲取更多VUE相關(guān)資料及項(xiàng)目可以關(guān)注:B站 小王學(xué)Java
1、Vue簡(jiǎn)介
現(xiàn)在的大前端時(shí)代,是一個(gè)動(dòng)蕩紛爭(zhēng)的時(shí)代,江湖中已經(jīng)分成了很多門派,主要以Vue,React還有Angular為首,形成前端框架三足鼎立的局勢(shì)。Vue在前端框架中的地位就像曾經(jīng)的jQuery,由于其簡(jiǎn)單易懂、開(kāi)發(fā)效率高,已經(jīng)成為了前端工程師必不可少的技能之一。
Vue是一種漸進(jìn)式JavaScript框架,完美融合了第三方插件和UI組件庫(kù),它和jQuery最大的區(qū)別在于,Vue無(wú)需開(kāi)發(fā)人員直接操作DOM節(jié)點(diǎn),就可以改變頁(yè)面渲染內(nèi)容,在應(yīng)用開(kāi)發(fā)者具有一定的HTML、CSS、JavaScript的基礎(chǔ)上,能夠快速上手,開(kāi)發(fā)出優(yōu)雅、簡(jiǎn)潔的應(yīng)用程序模塊。
但是我們提及Vue的時(shí)候,更多的是關(guān)注它的用法,而不是學(xué)習(xí)它是如何解決前端問(wèn)題的,這多少有點(diǎn)亞健康。有前端開(kāi)發(fā)經(jīng)驗(yàn)的人,一定在開(kāi)發(fā)過(guò)程中遇到過(guò)奇奇怪怪的問(wèn)題,然后稀里糊涂地解決,倘若再次遇到相似的問(wèn)題,便再次手足無(wú)措,作為一名前端工程師,在遇到問(wèn)題的時(shí)候我們是否能準(zhǔn)確定位產(chǎn)生問(wèn)題的原因并及時(shí)解決,主要取決于我們對(duì)前端框架的理解是否足夠深入。
2、Vue實(shí)現(xiàn)原理
2.1 虛擬DOM(Virtual DOM)
隨著時(shí)代的發(fā)展,Web應(yīng)用的頁(yè)面交互效果越來(lái)越復(fù)雜,頁(yè)面功能越來(lái)越豐富,需要維護(hù)的狀態(tài)越來(lái)越多,DOM操作也越來(lái)越頻繁。DOM操作雖然簡(jiǎn)單易用,但是會(huì)產(chǎn)生不好維護(hù)的問(wèn)題。
在程序執(zhí)行的過(guò)程中,Watcher初始化時(shí)會(huì)將每一個(gè)節(jié)點(diǎn)和狀態(tài)進(jìn)行一一關(guān)聯(lián)和映射,setter監(jiān)聽(tīng)到Data的狀態(tài)發(fā)生改變后,就會(huì)通知Watcher,Watcher會(huì)將這些變化通知曾經(jīng)記錄過(guò)的DOM以及跟這些狀態(tài)相關(guān)的節(jié)點(diǎn),從而觸發(fā)頁(yè)面的渲染過(guò)程。組件接收到狀態(tài)變化后,會(huì)通過(guò)編譯將模板轉(zhuǎn)換成渲染函數(shù)Render,執(zhí)行渲染函數(shù)就會(huì)得到一個(gè)虛擬DOM樹,通過(guò)對(duì)比舊的虛擬DOM和新生成的虛擬DOM樹,來(lái)更新對(duì)應(yīng)的實(shí)際DOM節(jié)點(diǎn),執(zhí)行頁(yè)面渲染。
主流前端框架幾乎都在使用虛擬DOM,但是在使用虛擬DOM的時(shí)候,Angular和React都無(wú)法確定具體是哪個(gè)狀態(tài)發(fā)生了變化,因此需要在舊的虛擬DOM和新的虛擬DOM之間進(jìn)行暴力對(duì)比,但Vue從1.0版本開(kāi)始,就通過(guò)細(xì)粒度的綁定來(lái)更新視圖,也就是說(shuō),當(dāng)狀態(tài)發(fā)生變化的時(shí)候Vue可以知道具體是哪個(gè)狀態(tài)哪些節(jié)點(diǎn)需要發(fā)生改變,從而對(duì)這個(gè)節(jié)點(diǎn)執(zhí)行更新,然而這種細(xì)粒度的變化偵測(cè)會(huì)有一些內(nèi)存開(kāi)銷影響性能,一個(gè)項(xiàng)目越復(fù)雜,開(kāi)銷就越大。
Vue從2.0版本后,為了優(yōu)化性能,引入了虛擬DOM,選擇了一個(gè)折中的方案,既不需要暴力對(duì)比整個(gè)新舊虛擬DOM,也不需要通過(guò)細(xì)粒度的綁定來(lái)實(shí)現(xiàn)視圖的更新,即以組件為單位進(jìn)行Watcher監(jiān)聽(tīng),也就是說(shuō)即便一個(gè)組件內(nèi)有多個(gè)節(jié)點(diǎn)使用了某個(gè)狀態(tài),也只需一個(gè)Watcher來(lái)監(jiān)聽(tīng)這個(gè)狀態(tài)的變化,當(dāng)這個(gè)狀態(tài)發(fā)生變化時(shí),Watcher通知組件,組件內(nèi)部通過(guò)虛擬DOM的方式去進(jìn)行節(jié)點(diǎn)的對(duì)比和重新渲染。
2.2 常用指令實(shí)現(xiàn)原理
指令是指Vue提供的以“v-”前綴的特性,當(dāng)指令中表達(dá)式的內(nèi)容發(fā)生變化時(shí),會(huì)連帶影響DOM內(nèi)容發(fā)生變化。Vue.directive全局API可以創(chuàng)建自定義指令,并獲取全局指令,除了自定義指令,Vue還內(nèi)置了一些開(kāi)發(fā)過(guò)程中常用的指令,如v-if、v-for等。在Vue模板解析時(shí),會(huì)將指令解析到AST,使用AST生成字符串的過(guò)程中實(shí)現(xiàn)指令的功能。
在解析模板時(shí),會(huì)將節(jié)點(diǎn)上的指令解析出來(lái)并添加到AST的directives屬性中,directives將數(shù)據(jù)發(fā)送到VNode中,在虛擬DOM進(jìn)行頁(yè)面渲染時(shí),會(huì)觸發(fā)某些鉤子函數(shù),當(dāng)鉤子函數(shù)被觸發(fā)后,就說(shuō)明指令已生效。
2.2.1 v-if指令原理
在應(yīng)用程序中使用v-if指令:
在編譯階段生成:
在代碼執(zhí)行時(shí),會(huì)根據(jù)create的值來(lái)選擇創(chuàng)建哪個(gè)節(jié)點(diǎn)。
2.2.2 v-for指令原理
在應(yīng)用程序中使用v-for指令:
在編譯階段生成:
_l是renderList的別名,執(zhí)行代碼時(shí),_l函數(shù)會(huì)循環(huán)list變量,調(diào)用第二個(gè)參數(shù)中傳遞的函數(shù),傳遞兩個(gè)參數(shù):item和index,當(dāng)_c函數(shù)被調(diào)用時(shí),會(huì)執(zhí)行_v函數(shù),創(chuàng)建一個(gè)節(jié)點(diǎn)。
2.2.3 自定義指令原理
在應(yīng)用程序中,指令的處理邏輯分別監(jiān)聽(tīng)了create函數(shù)、update函數(shù)以及destory函數(shù),具體實(shí)現(xiàn)如下:
鉤子函數(shù)被觸發(fā)后,會(huì)執(zhí)行updateDirectives函數(shù),代碼如下:
在該函數(shù)中,不論是否存在舊虛擬節(jié)點(diǎn),只要其中存在directives,就會(huì)執(zhí)行_update函數(shù),_update函數(shù)代碼如下:
isCreate:判斷該虛擬節(jié)點(diǎn)是否是一個(gè)新建的節(jié)點(diǎn)。
isDistory:判斷是否刪除一個(gè)舊虛擬節(jié)點(diǎn)。
oldDirs:舊的指令集合,oldVnode中保存的指令。
newDirs:新的指令集合,vnode中保存的指令。
dirsWithInsert:觸發(fā)inserted指令鉤子函數(shù)的指令列表。
dirsWithPostpatch:觸發(fā)componentUpdated鉤子函數(shù)的指令列表。
通過(guò)normalizeDirectives函數(shù)將模板中使用的指令從用戶注冊(cè)的自定義指令集合中取出來(lái)的結(jié)果如下:
自定義指令的代碼為:
虛擬DOM在對(duì)比和渲染時(shí),會(huì)根據(jù)不同情景觸發(fā)不同的鉤子函數(shù),當(dāng)使用虛擬節(jié)點(diǎn)創(chuàng)建一個(gè)新的實(shí)際節(jié)點(diǎn)時(shí),會(huì)觸發(fā)create鉤子函數(shù),當(dāng)一個(gè)DOM節(jié)點(diǎn)插入到父節(jié)點(diǎn)時(shí),會(huì)觸發(fā)insert鉤子函數(shù)。
callHook函數(shù)執(zhí)行鉤子函數(shù)的方式如下:
callHook函數(shù)的參數(shù)意義分別為:
dir:指令對(duì)象。
hook:將要觸發(fā)的鉤子函數(shù)名。
vnode:新的虛擬節(jié)點(diǎn)。
oldVnode:舊的虛擬節(jié)點(diǎn)。
isDestory:判斷是否刪除一個(gè)舊虛擬節(jié)點(diǎn)。
虛擬DOM在渲染時(shí)會(huì)觸發(fā)的所有鉤子函數(shù)及其觸發(fā)機(jī)制如下:
需要注意的是,remove函數(shù)是只有一個(gè)元素從其父元素中移除時(shí)才會(huì)觸發(fā),如果該元素是被移除元素的子元素,則不會(huì)觸發(fā)remove函數(shù)。
感謝大家的認(rèn)同與支持,小編會(huì)持續(xù)轉(zhuǎn)發(fā)《樂(lè)字節(jié)》優(yōu)質(zhì)文章