原生JS實現(xiàn)輕量Vue+指令解析+變異數(shù)組監(jiān)聽

本章涉及知識點

1、前言

2喇聊、ZVue架構(gòu)設(shè)計

3、框架的功能列表

4蹦狂、ZVue類的屬性定義

5誓篱、_observer方法定義

6、_complie方法定義

7凯楔、v-model和v-bind指令解析

8窜骄、v-for循環(huán)指令解析

9、v-click點擊指令解析

10摆屯、Watcher類的屬性定義

11邻遏、Watcher動態(tài)批量刪除DOM方法

12、Watcher動態(tài)批量添加DOM方法

13鸥拧、Watcher動態(tài)更新DOM方法

14党远、變異數(shù)組類的屬性定義

15削解、變異數(shù)組切面調(diào)用回調(diào)函數(shù)

16富弦、案例頁面引用ZVue框架

17、案例結(jié)果的展示分析

18氛驮、后記

一腕柜、前言

寫完了幾篇數(shù)學算法的推導,突發(fā)奇想來換個角度寫一點關(guān)于前端的框架原理算法,于是就嘗試寫了這個輕量的框架—ZVue盏缤,大致上模擬了Vue漸進式框架的MVVM邏輯流程砰蠢,也是自己對Vue框架原理的一些感悟和心得體會

該框架可以實現(xiàn)動態(tài)的data劫持監(jiān)聽和指令解析、增刪改查整個數(shù)組字面量或者若干數(shù)組項字面量的時候唉铜,同時刷新view對應(yīng)的視圖台舱、事件的動態(tài)綁定,以及data和view的雙向綁定潭流。在page層實例ZVue的語法竞惋,html指令模板語法,包括渲染到瀏覽器端后的dom的結(jié)構(gòu)和原生Vue基本上相同

二灰嫉、ZVue整體架構(gòu)設(shè)計

梳理一下MVVM流程拆宛,需要動態(tài)劫持,解析指令讼撒,更新視圖浑厚,變異數(shù)組處理等,設(shè)計出的架構(gòu)圖如下

ZVue架構(gòu)設(shè)計圖

根據(jù)架構(gòu)圖根盒,類和函數(shù)的設(shè)計清單如下:

1:ZVue類

(1)constructor:初始化ZVue實例的數(shù)據(jù)集合钳幅、方法集合、template映射表和render映射表等

(2)_toNewArray:實例變異數(shù)組及注入回調(diào)函數(shù)

(3)_defineProperty:屬性劫持到變化炎滞,通知相應(yīng)的watcher對象刷新view

(4)_observer:深度遍歷所有屬性贡这,維護render映射表,并分派劫持監(jiān)聽

(5)_complie:遍歷dom結(jié)構(gòu)的所有指令厂榛,維護template映射表盖矫,分派到各自的解析函數(shù)

(6)_parsing_v_model:解析v-model指令,綁定input事件和watcher對象

(7)_parsing_v_click:解析v-click指令击奶,綁定click事件辈双,解析事件的參數(shù)列表

(8)_parsing_v_bind:解析v-bind指令和對應(yīng)的watcher對象

(9)_parsing_v_for:解析v-for指令,作用于整個數(shù)組柜砾,循環(huán)生成動態(tài)dom湃望,為父節(jié)點綁定watcher對象

(10)_parsing_v_for_item:遍歷v-for下的動態(tài)dom,綁定watcher對象

(11)_deleteArrayWatcher:動態(tài)維護刪除render的映射表

(12)_maintainTemplate:動態(tài)維護template映射表痰驱,并為真實dom設(shè)置v-data唯一標志

二证芭、Watcher類

(1)constructor:初始化data綁定的視圖片段,包含真實的dom担映,dom的屬性废士,data的key,ZVue的指針等

(2)getTemplateDom:根據(jù)dom字符串蝇完,動態(tài)組裝出包含標簽官硝、類名矗蕊、內(nèi)容以及自定義指令的dom模板

(3)deleteBatchDom:動態(tài)批量刪除dom,并同步維護render映射表

(4)addBatchDom:動態(tài)批量添加dom氢架,并同步劫持監(jiān)聽新的屬性值以及解析新的指令

(5)update_Array:更新數(shù)組類型的視圖片段

(6)update_Text:更新普通標簽中的視圖片段

(7)update:set鉤子通知觸發(fā)傻咖,負責通知屬性對應(yīng)的更新函數(shù)來刷新視圖

三、NewArray類(繼承Array類)

(1)constructor:接受參數(shù)列表和ZVue注入的回調(diào)函數(shù)岖研,調(diào)用父級的構(gòu)造函數(shù)

(2)push:重載Array類的push方法卿操,并在切面調(diào)用ZVue的回調(diào)函數(shù)

(3)pop:重載Array類的pop方法,并在切面調(diào)用ZVue的回調(diào)函數(shù)

(4)splice:重載Array類的splice方法孙援,并在切面調(diào)用ZVue的回調(diào)函數(shù)

三硬纤、架構(gòu)的功能列表

有了架構(gòu)圖和函數(shù)設(shè)計列表,此架構(gòu)的功能列表為:

(1)頁面ZVue對象的data和methods接管

(2)頁面的模板節(jié)點結(jié)構(gòu)赃磨、插值表達式的正確渲染和節(jié)點事件的綁定

(3)實現(xiàn)v-model筝家、v-bind、v-click邻辉、v-for四個指令的正確解析渲染

(4)Input輸入測試v-model雙向綁定溪王,頁面的值隨著Input的輸入值變化而同步變化

(5)dl列表測試v-for循環(huán)生成若干個dd(包含class和若干指令),且插值表達式包含常量+索引變量+數(shù)組項數(shù)值變量

(6)button點擊測試更新整個數(shù)組的字面量值骇,頁面的列表同步變化

(7)button點擊測試局部更新數(shù)組的某一項字面量莹菱,頁面的列表同步變化

(8)button點擊測試push數(shù)組,頁面的列表同步變化

(9)button點擊測試pop數(shù)組吱瘩,頁面的列表同步變化

(10)button點擊測試splice數(shù)組道伟,頁面的列表同步變化

四、ZVue類的屬性定義

ZVue類的屬性定義

需要注意原始數(shù)組類型需要賦值為變異數(shù)組使碾,才能進行數(shù)組API的切面編程

五咖驮、_observer方法定義

_observer方法

需要注意遍歷到數(shù)組類型的時候陷谱,需要初始化整個數(shù)組指針的render映射表并深度遍歷,到遍歷到數(shù)組項的時候,render映射表需要額外deep一層际长,顯然普通類型铃剔、數(shù)組指針和數(shù)組任意一項都被劫持费变,渲染后data結(jié)果為

數(shù)組整體和局部的劫持

六粥帚、_complie方法定義

_complie方法

分派到各自的指令函數(shù)解析后,render映射表為

render映射表

七祟剔、v-model和v-bind指令解析

v-model指令
v-bind指令

可以看到指令解析里隔躲,注入了與data對應(yīng)的watcher對象負責更新對應(yīng)的view

八、v-for循環(huán)指令解析

v-for指令

需要注意的是_parsing_v_for需要解析參數(shù)列表(可能包含數(shù)組索引或者數(shù)值物延,或者同時都包含)宣旱,最后是給節(jié)點的父節(jié)點綁定了watcher對象,該對象只負責刪除原來舊列表和生成新列表教届,而生成的列表節(jié)點還沒有被劫持和解析指令响鹃,所以需要重新劫持和解析新的節(jié)點

v_for_item方法

可以看到_parsing_v_for_item給每一個新節(jié)點注入了對應(yīng)的watcher對象,同時還檢測了新節(jié)點是否包含v-click指令案训,如果包含則調(diào)用其的解析函數(shù)买置,這也就是架構(gòu)圖中_parsing_v_for_item需要在watcher動態(tài)添加節(jié)點之后調(diào)用

九、v-click點擊指令解析

v-click指令-1
v-click指令-2

可以看到v-click指令需要先解析待調(diào)用的函數(shù)名字和參數(shù)列表强霎,同時要注意向上檢測父節(jié)點來判斷當前節(jié)點是否是循環(huán)生成的這種情況忿项,因為如果是循環(huán)生成的節(jié)點,需要二次從v-for指令中解析轉(zhuǎn)義參數(shù)列表為迭代數(shù)組的索引和數(shù)組項城舞,最后在調(diào)用原生的方法并傳入解析轉(zhuǎn)義的參數(shù)列表

十轩触、Watcher類的屬性定義

Watcher類

需要注意repalce是保存了迭代數(shù)組的key名稱集合,來更新替換循環(huán)dom的插值表達式

十一家夺、Watcher動態(tài)批量刪除DOM方法

動態(tài)批量刪除dom

該方法是配合v-for指令使用脱柱,注意需要在刪除舊dom的同時,需要維護ZVue的render映射表

十二拉馋、Watcher動態(tài)批量添加DOM方法

動態(tài)批量添加dom

該方法是配合v-for指令使用榨为,注意需要先從template映射表中讀取到dom的字符串模板,在動態(tài)組裝成dom節(jié)點煌茴,并根據(jù)新數(shù)組的長度循環(huán)生成新dom随闺,而這些新dom此刻并沒有被ZVue劫持屬性和解析指令,所以在循環(huán)結(jié)束后需要同步劫持新的屬性值和解析新dom的指令

其中動態(tài)根據(jù)dom字符串來正則解析組裝dom的方法定義為

getTemplateDom方法

十三蔓腐、Watcher動態(tài)更新DOM方法

dom更新方法

需要判斷當數(shù)據(jù)屬于數(shù)組類型矩乐,而數(shù)組類型的更新需要動態(tài)刪除、添加回论、維護render映射表散罕、重新劫持和解析指令,所以單獨封裝出數(shù)組的更新方法為

dom數(shù)組更新方法

十四傀蓉、變異數(shù)組類的屬性定義

變異數(shù)組屬性

需要注意到如splice方法的底層實現(xiàn)也許使用了中間數(shù)組來橋接原數(shù)組笨使,這樣會導致重復執(zhí)行回調(diào)函數(shù),而變異數(shù)組的聲明是在ZVue的構(gòu)造函數(shù)或者set鉤子里僚害,所以才可以帶上具名的回調(diào)函數(shù)硫椰,為此,需要判斷如果是變異數(shù)組內(nèi)部構(gòu)造了另一個變異數(shù)組萨蚕,則不會帶上回調(diào)函數(shù)的情況

十五靶草、變異數(shù)組切面調(diào)用回調(diào)函數(shù)

切面調(diào)用回調(diào)函數(shù)

這樣調(diào)用變異數(shù)組的push、pop岳遥、splice方法都會在執(zhí)行完原生數(shù)組的這些方法之后調(diào)用我們的回調(diào)函數(shù)奕翔,而這個回調(diào)函數(shù)要做的,就是更新ZVue中對應(yīng)的數(shù)組浩蓉,并且是數(shù)組本身字面量的直接覆蓋派继,才能讓數(shù)組本身發(fā)生變化宾袜,從而進入其set鉤子里去通知相應(yīng)的watcher對象刷新其視圖片段

下面是我們ZVue回調(diào)函數(shù)的定義

回調(diào)函數(shù)-1
回調(diào)函數(shù)-2

我們只希望數(shù)組本身被注入set和get鉤子,為此我們將data的名稱當做變量作為回調(diào)函數(shù)的名稱驾窟,使用eval來聲明具名回調(diào)函數(shù)庆猫,并為該回調(diào)函數(shù)注入靜態(tài)變量—ZVue實例指針,這樣就可以在回調(diào)函數(shù)內(nèi)部訪問到ZVue的屬性

十六绅络、案例頁面引用ZVue框架

下面我們編寫案例頁面來引用ZVue

案例頁面代碼-1

頁面html代碼部分和Vue非常相似~可以寫不同的指令和插值表達式

下面我們在頁面內(nèi)引入ZVue并實例

案例頁面代碼-2
案例頁面代碼-3

可以看到月培,頁面的js代碼部分和原生Vue非常相似~其中我們用隨機數(shù)來作為數(shù)組項來模擬測試增刪改查

十七、案例結(jié)果的展示分析

頁面渲染結(jié)果

觀察渲染的dom結(jié)構(gòu)為

頁面的dom渲染結(jié)構(gòu)

可以看到渲染后dom結(jié)構(gòu)和Vue非常接近恩急。下面我們輸入input或者點擊增加減少按鈕來測試頁面的雙向綁定

測試雙向綁定

下面我們來測試數(shù)組的變化杉畜,隨意push三個隨機值到數(shù)組中,觀察數(shù)組的set和render映射表

push三個數(shù)組項
新數(shù)組項被劫持
新數(shù)組項加入映射表

可以看到新加入的數(shù)組項都被劫持和映射到render表中衷恭,下面我們點擊局部更新按鈕來更新數(shù)組的第二項

局部更新數(shù)組的第二項

下面我們pop出四個值此叠,得到

pop四次

下面我們splice刪除數(shù)組第二項,得到

splice刪除數(shù)組第二項

最后我們更新整個數(shù)組字面量為一個長度為4的新數(shù)組随珠,得到

更新整個數(shù)組字面量
更新整個數(shù)組后的data和render

可以看到我們更新覆蓋完整個數(shù)組字面量后拌蜘,data中l(wèi)ist里又動態(tài)注入了新數(shù)據(jù)的set鉤子且刪除了舊數(shù)據(jù)的set鉤子,render映射表也動態(tài)維護了新節(jié)點對應(yīng)的watcher對象且刪除了舊節(jié)點的watcher對象

十八牙丽、后記

寫完ZVue简卧,主要目的是從原理出發(fā)用原生JS來實現(xiàn)數(shù)據(jù)的劫持和指令的解析,以及數(shù)組的動態(tài)CURD映射到視圖的動態(tài)變化烤芦,并沒有加入虛擬dom的diff算法举娩,同時也是向Vue的作者尤雨溪致敬!

案例代碼見:原生JS實現(xiàn)輕量Vue+指令解析+變異數(shù)組監(jiān)聽

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末构罗,一起剝皮案震驚了整個濱河市铜涉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌遂唧,老刑警劉巖芙代,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異盖彭,居然都是意外死亡纹烹,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進店門召边,熙熙樓的掌柜王于貴愁眉苦臉地迎上來铺呵,“玉大人,你說我怎么就攤上這事隧熙∑遥” “怎么了?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長音念。 經(jīng)常有香客問我沪饺,道長,這世上最難降的妖魔是什么闷愤? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任整葡,我火速辦了婚禮,結(jié)果婚禮上肝谭,老公的妹妹穿的比我還像新娘掘宪。我一直安慰自己蛾扇,他們只是感情好攘烛,可當我...
    茶點故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著镀首,像睡著了一般坟漱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上更哄,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天芋齿,我揣著相機與錄音,去河邊找鬼成翩。 笑死觅捆,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的麻敌。 我是一名探鬼主播栅炒,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼术羔!你這毒婦竟也來了赢赊?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤级历,失蹤者是張志新(化名)和其女友劉穎释移,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體寥殖,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡玩讳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了嚼贡。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锋边。...
    茶點故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖编曼,靈堂內(nèi)的尸體忽然破棺而出豆巨,到底是詐尸還是另有隱情,我是刑警寧澤掐场,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布往扔,位于F島的核電站贩猎,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏萍膛。R本人自食惡果不足惜吭服,卻給世界環(huán)境...
    茶點故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蝗罗。 院中可真熱鬧艇棕,春花似錦、人聲如沸串塑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽桩匪。三九已至打瘪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間傻昙,已是汗流浹背闺骚。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留妆档,地道東北人僻爽。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像贾惦,于是被迫代替她去往敵國和親胸梆。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,507評論 2 359

推薦閱讀更多精彩內(nèi)容