關於一些Vue的文章。(4)

2021-07-29 16:55:57 字數 3529 閱讀 2297

diff演算法中的patchvnode方法,以及核心updatechildren方法。

在上篇中,我們談到,當vnode不為真實節點,且vnode與oldvnode為同一節點時,會呼叫patchvnode方法。

我們直接從原始碼上進行分析:

// patchvnode()有四個引數

// oldvnode: 舊的虛擬節點

// vnode: 新的虛擬節點

// insertedvnodequeue: 存在於整個patch中,用於收集patch中插入的vnode;

// removeonly: 這個在原始碼裡有提到,removeonly is a special flag used only by也就是說是特殊的flag,用於transition-group元件。

function

patchvnode

(oldvnode, vnode, insertedvnodequeue, removeonly)

// 如果不為同一引用,那說用新的vnode建立了。

// 如果vnode, oldvnode都為靜態節點,且vnode.key === oldvnode.key相等時,當vnode為轉殖節點,或者vnode有v-once指令時,只需把oldvnode對應的真實dom,以及元件例項都複製到vnode上。

if (istrue(vnode.isstatic) &&

istrue(oldvnode.isstatic) &&

vnode.key === oldvnode.key &&

(istrue(vnode.iscloned) || istrue(vnode.isonce)))

// 讓vnode引用到現在的真實dom,當elm修改的時候,會同步修改vnode.elm

const elm = vnode.elm = oldvnode.elm

const oldch = oldvnode.children

const ch = vnode.children

// 我們先patchvnode, 方法就是先呼叫全域性的update hook

// 然後呼叫data裡定義的update hook

if (isdef(data) && ispatchable(vnode))

// 如果vnode.text未定義

// 這裡有個值得注意的地方,具有text屬性的vnode不應該具備有children

// 對於abc123

的寫法應該是

// h('p', ['abc', h('i', '123')])

// 而不是, h('p', 'abc', [h('i', '123')])

// 因此,對text存在與否的情況需單獨拿出來分析

if (isundef(vnode.text)) else

if (isdef(ch)) else

if (isdef(oldch)) else

if (isdef(oldvnode.text))

} else

if (oldvnode.text !== vnode.text)

// 最後再呼叫 postpatch hook。

if (isdef(data))

}

接著說重點 當oldvnode.children與vnode.children都存在,且不相同時呼叫的updatechildren()方法, 同樣的,咱們從原始碼上分析:

// updatechildren(),有五個引數

// parentelm: oldvnode.elm 的引用

// oldch, newch: 分別是上面分析中的oldvnode.children, vnode.children

// insertedvnodequeue, removeonly 請參考上面。

function

updatechildren

(parentelm, oldch, newch, insertedvnodequeue, removeonly)

// 當oldstartindex > oldendidx 或者 newstartindex > newendidx, 停止遍歷。

while (oldstartidx <= oldendidx && newstartidx <= newendidx) else

if (samevnode(oldstartvnode, newstartvnode)) else

if (samevnode(oldendvnode, newendvnode)) else

if (samevnode(oldstartvnode, newendvnode)) else

if (samevnode(oldendvnode, newstartvnode)) else else

// 如果根據vnode.key找出的elmtomove與newstartvnode值得比較比較

// patchvnode這兩個節點

// 之後,需要把這個child設定為undefined

// 同時需要把oldstartvnode.elm的位置移到newstartvnode.elm之前,以免影響接下來的遍歷。

if (samevnode(elmtomove, newstartvnode)) else }}

}// 遍歷完成之後,存在兩種情況

// 如果 oldstartidx > oldendidx, 即oldch先遍歷完

// 位於 newstartidx與newendidx之間的節點都可認為是新的節點

if (oldstartidx > oldendidx) else

if (newstartidx > newendidx)

}

直接在原始碼上分析,可能有點亂,總結一下:

patchvnode共有以下情況:

如果vnodetext node,改變elm.textcontent

patchvnode有乙個值得注意的地方是,vdom中規定,具有text屬性的vnode不應該具備children,因此需把text node單獨拿出來分析。

updatechildren()方法共有5種比較方式,前四種無key的情況,後一種為有key的情況,當oldstartidx > oldendidx或者newstartidx > newoldstartidx的時候停止遍歷。

遍歷完成後,如果oldch先遍歷完,位於newstartidx與newendidx之間的節點都可認為是新的節點,呼叫相應的方法插入節點。如果newch先遍歷完,此時,位於oldstartidx與oldendidx之間的節點已經不存在了,呼叫removevnodes()方法移除節點。

完。

關於一些Vue的文章。(5)

前三篇裡,我們開始從render,template,el的渲染dom樹的優先順序,最終都編譯成render函式,而後得到vnode 虛擬dom 經過diff演算法後,得到真實dom。那麼問題來了?得到真實dom以後接下來該做什麼?以及怎麼做?照例,分享一篇文章,vue。官網,暫時還沒有找到一篇文章能...

關於一些Vue的文章。(7)

還有其他許多,就不一一枚舉出來了。有沒有看上了的?沒有我等下再來問。在這篇文章裡我將是這幾個月來對 vue 學習的乙個小結。vue 和其他的 mvvm 思路是類似的 主要是為了實現三個過程 observer 通過observer對data進行監聽,並且提供訂閱某個資料項的變化的能力。利用object...

關於一些Vue的文章。(5)

前三篇裡,我們開始從render,template,el的渲染dom樹的優先順序,最終都編譯成render函式,而後得到vnode 虛擬dom 經過diff演算法後,得到真實dom。那麼問題來了?得到真實dom以後接下來該做什麼?以及怎麼做?照例,分享一篇文章,vue。官網,暫時還沒有找到一篇文章能...