原始碼位址
diff演算法首先要明確乙個概念就是diff的物件是虛擬dom,更新真實dom則是diff演算法的結果
constructor (
。。。)
這個部分的** 主要是為了更好地知道在diff演算法中具體diff的屬性的含義,當然也可以更好地了解vnode例項
核心函式是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
// destroy old node
if (isdef(parentelm)) else if (isdef(oldvnode.tag))
插入過程簡化來說就是判斷node的type分別呼叫
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。
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)
}
乙個迴圈比較的幾種情況和處理(以下的++ --均指index的++ --)比較則是比較的node節點,簡略寫法 不嚴謹 比較用的是samevnode函式也不是真的全等
整體迴圈不結束的條件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...