原始碼位址
diff演算法首先要明確乙個概念就是diff的物件是虛擬dom,更新真實dom則是diff演算法的結果
這個部分的** 主要是為了更好地知道在diff演算法中具體diff的屬性的含義,當然也可以更好地了解vnode例項constructor (
。。。)
核心函式是patch函式
isundef判斷(是不是undefined或者null)
// empty mount (likely as component), create new root elementcreateelm(vnode, insertedvnodequeue) 這裡可以發現建立節點不是乙個乙個插入,而是放入乙個佇列中統一批處理
核心函式samevnode
function samevnode (a, b)
這裡是乙個外層的比較函式,直接去比較了兩個節點的key,tag(標籤),data的比較(注意這裡的data指的是vnodedata),input的話直接比較type。
這會確認兩個節點是否有進一步比較的價值,不然直接替換export inte***ce vnodedata ;
ref?: string;
tag?: string;
staticclass?: string;
class?: any;
staticstyle?: ;
style?: object | object;
props?: ;
attrs?: ;
domprops?: ;
hook?: ;
on?: ;
nativeon?: ;
transition?: object;
show?: boolean;
inlinetemplate?: ;
directives?: vnodedirective;
keepalive?: boolean;
}
替換的過程主要是乙個createelm函式 另外則是銷毀oldvnode
插入過程簡化來說就是判斷node的type分別呼叫// destroy old node
if (isdef(parentelm)) else if (isdef(oldvnode.tag))
createcomponent(會判斷是否有children然後遞迴呼叫)
createcomment
createtextnode
建立後使用insert函式
之後需要用hydrate函式將虛擬dom和真是dom進行對映
核心函式function insert (parent, elm, ref)
} else
}}
function patchvnode (oldvnode, vnode, insertedvnodequeue, removeonly)
const elm = vnode.elm = oldvnode.elm
if (istrue(oldvnode.isasyncplaceholder)) else
return
}if (istrue(vnode.isstatic) &&
istrue(oldvnode.isstatic) &&
vnode.key === oldvnode.key &&
(istrue(vnode.iscloned) || istrue(vnode.isonce))
) let i
const data = vnode.data
if (isdef(data) && isdef(i = data.hook) && isdef(i = i.prepatch))
const oldch = oldvnode.children
const ch = vnode.children
if (isdef(data) && ispatchable(vnode))
if (isundef(vnode.text)) else if (isdef(ch)) else if (isdef(oldch)) else if (isdef(oldvnode.text))
} else if (oldvnode.text !== vnode.text)
if (isdef(data))
}
const el = vnode.el = oldvnode.el 這是很重要的一步,讓vnode.el引用到現在的真實dom,當el修改時,vnode.el會同步變化。
這部分重點還是關注整個演算法
首先四個指標,oldstart,oldend,newstart,newend,兩個陣列,oldvnode,vnode。
乙個迴圈比較的幾種情況和處理(以下的++ --均指index的++ --)比較則是比較的node節點,簡略寫法 不嚴謹 比較用的是samevnode函式也不是真的全等function updatechildren (parentelm, oldch, newch, insertedvnodequeue, removeonly) else if (isundef(oldendvnode)) else if (samevnode(oldstartvnode, newstartvnode)) else if (samevnode(oldendvnode, newendvnode)) else if (samevnode(oldstartvnode, newendvnode)) else if (samevnode(oldendvnode, newstartvnode)) else else else
}newstartvnode = newch[++newstartidx]}}
if (oldstartidx > oldendidx) else if (newstartidx > newendidx)
}
整體迴圈不結束的條件oldstartidx <= oldendidx && newstartidx <= newendidx
oldstart === newstart,oldstart++ newstart++
oldend === newend,oldend-- newend--
oldstart === newend, oldstart插到隊伍末尾 oldstart++ newend--
oldend === newstart, oldend插到隊伍開頭 oldend-- newstart++
剩下的所有情況都走這個處理簡單的說也就兩種處理,處理後newstart++
newstart在old中發現一樣的那麼將這個移動到oldstart前
沒有發現一樣的那麼建立乙個放到oldstart之前
迴圈結束後並沒有完成
還有一段判斷才算完
if (oldstartidx > oldendidx) else if (newstartidx > newendidx)
簡單的說就是迴圈結束後,看四個指標中間的內容,old陣列中和new陣列中,多退少補而已
整體認識還很粗糙,不過以目前的水平和對vue的了解也就只能到這了
vue的diff演算法
1.當資料發生變化時,vue是怎麼更新節點的?渲染真實dom的開銷很大,比如我們修改了某個資料,如果直接渲染到真實dom會引起整個dom樹的重繪和重排,有沒有可能我們只更新我們修改的那一小塊dom而不更新整個dom呢?diff演算法可以幫助我們。我們根據真實dom生成乙個虛擬dom,當虛擬dom某個...
詳解vue的diff演算法
前言先來了解幾個點 1.當資料發生變化時,vue是怎麼更新節點的?要知道渲染真實dom的開銷是很大的,比如有時候我們修改了某個資料,如果直接渲染到真實dom上會引起整個dom樹的重繪和重排,有沒有可能我們只更新我們修改的那一小塊dom而不要更新整個dom呢?diff演算法能夠幫助我們。我們先根據真實...
vue的diff演算法理解
diff演算法作用 用來修改dom的一小段,不會引起dom樹的重繪diff演算法實現的原理 diff演算法將virtual dom的某個節點資料改變後生成的新的vnode與舊節點進行比較,並替換為新的節點,具體過程就是呼叫patch方法,比較新舊節點,一邊比較一邊給真實的dom打補丁進行替換func...