摘要:總共寫了四篇文章都是自己的一些拙見,僅供參考,請(qǐng)多多指教,我這邊也會(huì)持續(xù)修正加更新介紹一下基本用法介紹一下渲染原理介紹一下的算法和對(duì)值的認(rèn)識(shí)介紹一下對(duì)于兼容的修改這篇主要是說一下的算法在上一篇中我總結(jié)過對(duì)比渲染的流程大體分為通過來判斷兩個(gè)是
總共寫了四篇文章(都是自己的一些拙見,僅供參考,請(qǐng)多多指教,我這邊也會(huì)持續(xù)修正加更新)
介紹一下snabbdom基本用法
介紹一下snabbdom渲染原理
介紹一下snabddom的diff算法和對(duì)key值的認(rèn)識(shí)
介紹一下對(duì)于兼容IE8的修改
這篇主要是說一下snabbdom的diff算法
在上一篇中我總結(jié)過:
對(duì)比渲染的流程大體分為
1.通過sameVnode來判斷兩個(gè)vnode是否值得進(jìn)行比較
2.如果不值得,直接刪除舊的vnode,渲染新的vnode
3.如果值得,調(diào)用模塊鉤子函數(shù),對(duì)其節(jié)點(diǎn)的屬性進(jìn)行替換,例如style,event等;再判斷節(jié)點(diǎn)子節(jié)點(diǎn)是否為文本節(jié)點(diǎn),如果為文本節(jié)點(diǎn)則進(jìn)行更替,如果還存在其他子節(jié)點(diǎn)則調(diào)用updateChildren,對(duì)子節(jié)點(diǎn)進(jìn)行更新,更新流程將會(huì)回到第一步,重復(fù);
這篇文章的重點(diǎn)就是說一下updateChildren這個(gè)函數(shù)
sameVnodefunction sameVnode(vnode1, vnode2) { return vnode1.key === vnode2.key && vnode1.sel === vnode2.sel; }
這是一個(gè)比較兩個(gè)vnode是否相似,是否值得去進(jìn)行比較的函數(shù),那么這里為什么會(huì)提到它?因?yàn)檫@里面有一個(gè)很重要的值---key
在平時(shí)的使用中幾乎用不到這個(gè)key值,不會(huì)去專門給它一個(gè)定義值,因?yàn)閡ndefined===undefined,不會(huì)影響其比較;
key值的出現(xiàn)主要是為了應(yīng)付一些場(chǎng)景
例如:
對(duì)于這種情況,如果按照正常的做法,就是一個(gè)個(gè)vnode去進(jìn)行比較,發(fā)現(xiàn)其文本節(jié)點(diǎn)不對(duì),就會(huì)一個(gè)個(gè)進(jìn)行替換例如:
對(duì)于這種情況是否可以優(yōu)化呢?
答案是可以的,我們可以刪除
那這里就涉及到一個(gè)標(biāo)記值,標(biāo)記著在新vnode中還有哪些舊的vnode存在,key值就是充當(dāng)著這個(gè)角色。
[1(key:a),2(key:b),3(key:c)]
[2(key:b),3(key:c),4(key:d)]
[a,b,c] -> [a(x),b,c,d(+)] === [1,2,3] --> [1(x),2,3,4(+)]
key值與vnode形成了一個(gè)映射,可以看到,我們通過對(duì)key值的排序、增刪間接完成了對(duì)vnode的操作,使用最少的dom操作來完成了
如何對(duì)key值進(jìn)行排序,增刪那這里就會(huì)有一個(gè)問題,我們?nèi)绾瓮瓿缮厦娴牟僮髂兀窟@個(gè)過程我們可以理解為一種優(yōu)化對(duì)比渲染的過程,也就是diff算法的核心
建議大家先看一下這一篇文章,圖文并茂
我這邊舉一個(gè)復(fù)雜的例子,記錄每一步的操作:
下面是頁(yè)面真實(shí)的dom,分別保存在自己vnode的elm屬性上;舊-->新
假設(shè)每個(gè)元素都有一個(gè)key值一一對(duì)應(yīng),且不重復(fù),它們的key值分別為
a:1 a:1 b:2 d:6 c:3 f:4 f:4 --> h:8 e:5 k:9 d:6 b:2 g:7 g:7
將舊新vnode分別放入兩個(gè)數(shù)組
old:[vnode,....] new:[vnode,....]
其實(shí)我們是比較其key值是否相等,然后再?zèng)Q定如何排序,增刪vnode的位置,patch vnode,最終達(dá)到改變dom的目的,為了方便理解,我這里把其key值拿出來放入一個(gè)數(shù)組,每一個(gè)key在數(shù)組中的索引都對(duì)應(yīng)著相應(yīng)的vnode在其數(shù)組中的索引,在真實(shí)代碼中是直接比較vnode.key值。
oldKey:[1,2,3,4,5,6,7] oldStartIdx:0 oldStartVal:1 oldEndIdx:6 oldEndVal:7 newKey:[1,6,4,8,9,2,7] newStartIdx:0 newStartVal:1 newEndIdx:6 newEndVal:7
用的是雙指針的方法,頭尾同時(shí)開始掃描;
循環(huán)兩個(gè)數(shù)組,循環(huán)條件為(old_startIndex <= old_endIndex && new_startIndex <= new_endIndex)
(下面說的patch是直接對(duì)vnoe.elm進(jìn)行修改,調(diào)用前面的patchVnode函數(shù),也就是直接對(duì)頁(yè)面的dom進(jìn)行修改,及時(shí)比較及時(shí)修改)
比較oldStartVal和newStartVal是否相等,如果相等則oldStartIdx和newStartIdx分別加1,并對(duì)oldStartVal對(duì)應(yīng)的vnode進(jìn)行patch,進(jìn)入下一次循環(huán);這個(gè)例子中oldStartVal==newStartVal,所以oldStartIdx:1 newStartIdx:1;若不相等,繼續(xù)比較;
比較過后: oldStartIdx:1 oldEndIdx:6 oldStartVal:2 oldEndVal:7 newStartIdx:1 newEndIdx:6 newStartVal:6 newEndVal:7 比較范圍縮小后: oldKey:[2,3,4,5,6,7] newKey:[6,4,8,9,2,7] dom:
比較oldEndVal和newEndVal是否相等,如果相等則oldEndIdx和newEndIdx分別減1,并對(duì)oldEndVal對(duì)應(yīng)的舊vnode進(jìn)行patch,進(jìn)入下一次循環(huán);這里oldEndVal==newEndVal,所以oldEndIdx:5 newEndIdx:5;若不相等,繼續(xù)比較;
比較過后: oldStartIdx:1 oldEndIdx:5 oldStartVal:2 oldEndVal:6 newStartIdx:1 newEndIdx:5 newStartVal:6 newEndVal:2 比較范圍縮小后: oldKey:[2,3,4,5,6] newKey:[6,4,8,9,2] dom:
比較oldStartVal和newEndVal是否相等,如果相等則oldStartIdx和newEndIdx分別加1和減1,oldStartVal對(duì)應(yīng)的vnode移動(dòng)到oldEndVal對(duì)應(yīng)的vnode后面,并對(duì)移動(dòng)的vnode進(jìn)行patch,進(jìn)入下一次循環(huán);這里oldStartVal==newEndVal,所以oldStartIdx:2 newEndIdx:4;若不相等,繼續(xù)比較;
比較過后: oldStartIdx:2 oldEndIdx:5 oldStartVal:3 oldEndVal:6 newStartIdx:1 newEndIdx:4 newStartVal:6 newEndVal:9 比較范圍縮小后: oldKey:[3,4,5,6] newKey:[6,4,8,9] dom:
比較oldEndVal和newStartVal是否相等,如果相等則oldEndIdx和newStartIdx分別減1和加1,oldEndVal對(duì)應(yīng)的vnode移動(dòng)到oldStart對(duì)應(yīng)的vnode前面,并對(duì)移動(dòng)的vnode進(jìn)行patch,進(jìn)入下一次循環(huán);這里oldEndVal==newStartVal,所以oldEndIdx:4 newStartIdx:2;若不相等,繼續(xù)比較;
比較過后: oldStartIdx:2 oldEndIdx:4 oldStartVal:3 oldEndVal:5 newStartIdx:2 newEndIdx:4 newStartVal:4 newEndVal:9 比較范圍縮小后: oldKey:[3,4,5] newKey:[4,8,9] dom:
若不滿足上述判斷條件,查找newStartVal對(duì)應(yīng)的vnode是否存在于舊vnode數(shù)組中。若存在,移動(dòng)這個(gè)舊的vnode到oldStartVal對(duì)應(yīng)的vnode前面,并對(duì)這個(gè)移動(dòng)的vnode進(jìn)行patch,在舊的vnode數(shù)組中將其原來的位置置為undefined,并且newStartIdx加1;
比較過后: oldStartIdx:2 oldEndIdx:4 oldStartVal:3 oldEndVal:5 newStartIdx:3 newEndIdx:4 newStartVal:8 newEndVal:9 比較范圍縮小后: oldKey:[3,4,5] newKey:[8,9] dom:
若不存在,則將這個(gè)newStartVal對(duì)應(yīng)的vnde添加到oldStartVal對(duì)應(yīng)的vnode前面,并且newStartIdx加1;
比較過后: oldStartIdx:2 oldEndIdx:4 oldStartVal:3 oldEndVal:5 newStartIdx:4 newEndIdx:4 newStartVal:9 newEndVal:9 比較范圍縮小后: oldKey:[3,4,5] newKey:[9] dom:
循環(huán)結(jié)束,判斷新舊vnode的key值哪個(gè)遍歷完,如果舊的便利完,若舊vnode數(shù)組遍歷完,則將剩余的新vnode數(shù)組中的vnode進(jìn)行添加;若新vnode數(shù)組遍歷完,則刪除剩余的舊vnode數(shù)組中的vnode
在上面例子中,我們需要?jiǎng)h除oldVnodeArray中的三個(gè)vnode,索引分別為3,4,5,從而刪除了vnode對(duì)應(yīng)的elm
最后得到最終的dom結(jié)構(gòu)
上面的例子沒有將所有情況全部歸納進(jìn)來,不過應(yīng)該包含了大部分情況了。還需要注意的就是:
上面只是提到了key值,其實(shí)比較兩個(gè)vnode是否相似還有一個(gè)sel屬性,必須要兩個(gè)都相等才行
正常情況下key值用到的地方也是ul-li tr-td這種子元素重復(fù)的場(chǎng)景,因?yàn)檫@種情況下才會(huì)涉及到子元素順序改變還能復(fù)用
通過上面的分析,其實(shí)還可以發(fā)現(xiàn)一個(gè)key值的特點(diǎn),就是唯一性和一一對(duì)應(yīng)性。唯一性好理解,畢竟key值就是用來每個(gè)vnode自己的標(biāo)示;一一對(duì)應(yīng)代表著是你舊vnode和新vnode中如果沒有改變,則其key值應(yīng)保持不變,之所以要提這個(gè)是因?yàn)楹芏嗟胤娇吹搅诉M(jìn)行循環(huán)渲染的時(shí)候其key值都是用的數(shù)組的index進(jìn)行賦值
如果考慮這種情況
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/100371.html
摘要:毫無疑問的是算法的復(fù)雜度與效率是決定能夠帶來性能提升效果的關(guān)鍵因素。速度略有損失,但可讀性大大提高。因此目前的主流算法趨向一致,在主要思路上,與的方式基本相同。在里面實(shí)現(xiàn)了的算法與支持。是唯一添加的方法所以只發(fā)生在中。 VirtualDOM是react在組件化開發(fā)場(chǎng)景下,針對(duì)DOM重排重繪性能瓶頸作出的重要優(yōu)化方案,而他最具價(jià)值的核心功能是如何識(shí)別并保存新舊節(jié)點(diǎn)數(shù)據(jù)結(jié)構(gòu)之間差異的方法,...
摘要:閑聊在學(xué)的過程中,虛擬應(yīng)該是聽的最多的概念之一,得知其是借鑒進(jìn)行開發(fā),故習(xí)之。以我的觀點(diǎn)來看,多個(gè)相同元素渲染時(shí),則需要為每個(gè)元素添加值。 閑聊:在學(xué)vue的過程中,虛擬dom應(yīng)該是聽的最多的概念之一,得知其是借鑒snabbdom.js進(jìn)行開發(fā),故習(xí)之。由于我工作處于IE8的環(huán)境,對(duì)ES6,TS這些知識(shí)的練習(xí)也只是淺嘗輒止,而snabbdom.js從v.0.5.4這個(gè)版本后開始使用TS...
摘要:這個(gè)大概是的鉤子吧在每一次插入操作的時(shí)候都將節(jié)點(diǎn)這類型方法可以看出來是在調(diào)用對(duì)應(yīng)的方法因?yàn)殚_始的時(shí)候就導(dǎo)入進(jìn)來了插入節(jié)點(diǎn)操作的時(shí)候都需要加入子節(jié)點(diǎn)有子元素也就是的時(shí)候遞歸調(diào)用循環(huán)子節(jié)點(diǎn)生成對(duì)應(yīng)著一些操作之后都要觸發(fā)鉤子函數(shù)。 snabbdom 本文的snabbdom源碼分析采用的是0.54版本(即未用ts重寫前的最后一版) 前期了解 snabbdom被用作vue的虛擬dom。本文的一個(gè)...
摘要:總共寫了四篇文章都是自己的一些拙見,僅供參考,請(qǐng)多多指教,我這邊也會(huì)持續(xù)修正加更新介紹一下基本用法介紹一下渲染原理介紹一下的算法和對(duì)值的認(rèn)識(shí)介紹一下對(duì)于兼容的修改這篇主要是記錄一下針對(duì)做了哪些修改增加用來兼容某些功能函數(shù),例如等將每個(gè)文件單 總共寫了四篇文章(都是自己的一些拙見,僅供參考,請(qǐng)多多指教,我這邊也會(huì)持續(xù)修正加更新) 介紹一下snabbdom基本用法 介紹一下snabbdo...
摘要:如果新舊的和都相同,說明兩個(gè)相似,我們就可以保留舊的節(jié)點(diǎn),再具體去比較其差異性,在舊的上進(jìn)行打補(bǔ)丁否則直接替換節(jié)點(diǎn)。 總共寫了四篇文章(都是自己的一些拙見,僅供參考,請(qǐng)多多指教,我這邊也會(huì)持續(xù)修正加更新) 介紹一下snabbdom基本用法 介紹一下snabbdom渲染原理 介紹一下snabddom的diff算法和對(duì)key值的認(rèn)識(shí) 介紹一下對(duì)于兼容IE8的修改 這篇我將以自己的思路去...
閱讀 2133·2021-11-22 15:24
閱讀 2428·2021-09-09 11:53
閱讀 3047·2021-09-04 16:40
閱讀 1646·2019-08-30 15:52
閱讀 3366·2019-08-29 13:47
閱讀 2747·2019-08-26 17:40
閱讀 1554·2019-08-26 13:24
閱讀 2255·2019-08-26 12:01