當前位置:首頁 » 操作系統 » vue和演算法

vue和演算法

發布時間: 2023-05-18 22:03:10

㈠ Vue2.x和Vue3.x渲染器的diff演算法

簡單來說,diff演算法有以下過程

正常Diff兩個樹的時間復雜度是 O(n^3) ,但實際情況下我們很少會進行 跨層級的移動DOM ,所以Vue將Diff進行了優化,從 O(n^3) -> O(n) ,只有當新舊children都為多個子節點時才需要用核心的Diff演算法進行同層級比較。

Vue2的核心Diff演算法採用了 雙端比較 的演算法,同時從新舊children的兩端開始進行比較,藉助key值找到可復用的節點,再進行相關操作。相比React的Diff演算法,同樣情況下可以減少移動節點次數,減少不必要的性能損耗,更加的優雅。

Vue3.x借鑒了 ivi 演算法和 inferno 演算法

在創建VNode時就確定其類型,以及在 mount/patch 的過程中採用 位運算 來判斷一個VNode的類型,在這個基礎之上再配合核心的Diff演算法,使得性能困棚上較Vue2.x有了提升。(實悄宴際的實現可以結合Vue3.x源碼看。)

該演算法中還運用了 動態規劃 的思想求解最長遞歸子啟尺銀序列。

㈡ vue和react的diff演算法比較

相同點:
Vue和react的diff演算法,都是不進行跨層級比較,只做同級比較。

不同點:

1.Vue進行diff時,調用patch打補丁函數,一邊比較一邊給真實的DOM打補丁
2.Vue對比節點,當節點漏粗元素類型相同,但是className不同時,認為是不同類型的元素,刪除重新創建,而react則認為是同類型節點,進行修改操作
3.① Vue的列表比對,採用從兩端到中間的方式,舊集合和新集合兩端各歷液存在兩個指針,兩兩進行比較,如果匹配上了就按照新集合去調整舊集合,每次對比結束後,指針向隊列中間移動;
②而react則是從左往右依次對比,利用元素的index和標識lastIndex進行比較,如果滿足index < lastIndex就移動元返爛鎮素,刪除和添加則各自按照規則調整;
③當一個集合把最後一個節點移動到最前面,react會把前面的節點依次向後移動,而Vue只會把最後一個節點放在最前面,這樣的操作來看,Vue的diff性能是高於react的

㈢ 徹底理解vue的patch流程和diff演算法

上一篇 《vue非同步更新流程梳理》 梳理了數據從賦值到更新到視圖的整體流程。但是最後的步驟 vm._update(vm._render()) 只是粗略的提了一嘴,現在就仔細的研究它內部的細節,搞清楚patch流程和diff原理是我們看源碼的重中之重。

當更新數據的時候就會執行這個updateComponent方法,即方法裡面的 vm._update(vm._render()) ,vm.render() 得到一個vnode,那麼vm._update到底干什麼? 進去看看

至此,無論是初始化還是更新都是靠patch來完成的 ,我們只需要看update流程就可以了。進入patch內部

patch函數主要接收oldVnode 與 vnode兩個參數,其實就是新舊兩棵虛擬樹。這里經過判斷條件 !isRealElement && sameVnode(oldVnode, vnode),不是真實節點 且是相同的vnode,進入patchVnode(oldVnode, vnode, insertedVnodeQueue, null, null, removeOnly); 我們只要關注oldVnode, vnode這兩個參數即可。

按照我們的例子,此時的oldVnode 與 vnode分別是

此處只列出關鍵屬性tag, key, elm, children,elm,還有很多其他的屬性沒有列出。真實的虛擬樹節點應該是如下圖

我們能看出 兩個vnode之間就是children[0]的不同:

追蹤流程發現,我們進入oldVnode 與 vnode的children進行對比,在updateChildren函數昌跡中。

我們先不去看updateChildren的邏輯,繼續看patchVnode這個函數其他的邏輯分支,得出 oldVnode 與 vnode的對比流程

總結: patchVnode這個方法的主要作用是悉纖對比兩個虛擬節點過程中去更新真實dom

接下來我們進入updateChildren流程,這是兩個children的對比,看一下這個函數的定義

函數解讀:

下面是兩個數組進行diff的流程,也就是diff演算法

diff解讀:
新舊耐陸並兩個數組,都有雙端指針,兩端指針向中間靠攏,直到某個數組的兩端指針相交則退出循環。

在這個過程中,會先判斷是否有以下四種情況

如果不符合這4種情況,那就基於舊數組遍歷一次,拿到每個節點的key和index,就是oldKeyToIdx: {key1: 0, key2: 1}這種情況。然後去新數組首個節點開始匹配,匹配到就進行遞歸patchVnode流程,沒匹配到就進行創建新節點,插入到真實dom節點裡面去。

當循環結束,此時要麼是舊數組相交,要麼是新數組相交,只有這兩種情況:

至此diff流程結束。

兩個虛擬樹進行對比:
patch(oldVnode, vnode) -> patchVnode(oldVnode, vnode) -> updataChildren(oldCh, newCh)
在updataChildren(oldCh, newCh)的過程中也會進行 patchVnode(oldVnode, vnode) ,如此虛擬樹深度優先遞歸diff完成。

更加詳細直觀的圖看此鏈接
https://www.processon.com/view/5e809004e4b08e4e2447d02e

㈣ 簡單幾句話,知道什麼是迴流重繪、vue虛擬dom、diff演算法和key

1.什麼是vue虛擬dom。先知道什麼是dom樹。
眾所周知,一個頁面形成的流程。(順便聊一下迴流和重繪)
(1) 解析 HTML===>生成DOM樹
(2) 解析CSS===>生成CSSDOM樹
(3) Render Tree ===> 從Dom樹的根節點開始遍歷每個可見的節點(因為這裡面有display:none、scrpi等的,不被遍歷。)
對於每個可見的節點,找到其對應的CSSDOM規則,並且應用。
生成Render Tree 。
fine,問題來了,什麼是迴流呢?就是在生成render Tree 的時候,有的CSS涉及到了HTML的尺寸(width/height)、布局改變、隱藏等。詳細的可以去搜一下怎麼會造成迴流。<h3>所有的頁面都至少會有一次迴流,因為第一次生成render tree一定會迴流</h3>
Render Tree生成後,layout(布局)就完成了開始繪制(添加屬性,類似於顏色啊,大小啊之類的不會影響布局的屬性)。如果說不出意外你不去改的話這輩子和個Render Tree就永遠是這個樹了。HTML頁面就渲染結束了。
但是如果你想改。好嘛,我們就要開始判斷你改的是什麼了。如果說是影響布局的,那就是迴流===>重繪
如果說你只想改個顏色啥的那就直接是重繪,沒有迴流。
<h3>傑倫:迴流必然會帶來重繪,但是重繪不一定會迴流</h3>
關於如何優化,可以搜索迴流和重繪
參考圖:

好了,簡單的理解了一些html解析和dom樹的生成畢配流程。就可以解釋什麼是虛擬dom了。
虛擬dom也還是那個dom。那為啥不用真實的dom呢?因為真實的DOM你一操作,它立馬給你迴流重手孝指繪,可能你有10個事件在等著干,一個個都要迴流重繪一遍太影響性能了。
(高光打過來!)虛擬dom就站出來了。
虛擬dom:如果有10次更新dom的動作,虛擬dom不會立即操作dom,而是將這10次更新的內容儲存起來,通過diff演算法,把新的dom(vue剛構造的虛擬dom)和舊的dom(可能是頁面上現在顯示的真實的dom)進行對比。然後渲染對比完的DOM。
問題來了:什麼是diff呢?這是一個演算法,有興趣的可以自己搜一下詳細了解誒。我這里只是簡單的介紹說這個東西就是 :頭頭對比。肚子肚子對比。腳腳對比。同級對比,不會跨級對比。就是我的新頭和我的舊頭對比。我的新肚子和我的舊肚子對比。對比完了去頁面上生成一個新的我。

上面提到了patch階段,順便說一下key diff演算法會通過key可以判斷這兩個虛擬dom是不是同一個dom,所以我們key盡量都要寫慎前上,並且盡量不要使用索引作為key。可以使用 'xx-index' 方式寫key。方便你我它~~

好了。本文over 以上都是自己復習的時候總結的內容,如果有問題請留言 Thanks♪(・ω・)ノ

㈤ web前端diff 演算法深入一下

有同學問:能否詳細說一下 diff 演算法。

詳細的說,請閱讀這篇文章,有疑問的地方歡迎留言一起討論。

因為 diff 演算法是 vue2.x , vue3.x 以及 react 中關鍵核心點,理解 diff 演算法,更有助於理解各個框架本質。

說到「diff 演算法」,不得不說「虛擬 Dom」,因為這兩個息息相關。

比如:

等等

我們先來說說虛擬 Dom,就是通過 JS 模擬實現 DOM ,接下來難點就是如何判斷舊對象和新對象之間的差異。

Dom 是多叉樹結構,如果需要完整的對比兩棵樹的差異,那麼演算法的時間復雜度 O(n ^ 3),這個復雜度很難讓人接收,尤其在 n 很大的情況下,於是 React 團隊優化了演算法,實現了 O(n) 的復雜度來對比差異。

實現 O(n) 復雜度的關鍵就是只對比同層的節點,而不是跨層對比,這也是考慮到在實際業務中很少會去跨層的移動 DOM 元素。

虛擬 DOM 差異演算法的步驟分為 2 步:

實際 diff 演算法比較中,節點比較主要有 5 種規則的比較

部分源碼 https://github.com/vuejs/vue/blob//src/core/vdom/patch.js#L501 如下:

在 reconcileChildren 函數的入參中

diff 的兩個主體是:oldFiber(current.child)和 newChildren(nextChildren,新的 ReactElement),它們是兩個不一樣的數據結構。

部分源碼

很多時候手工優化 dom 確實會比 virtual dom 效率高,對於比較簡單的 dom 結構用手工優化沒有問題,但當頁面結構很龐大,結構很復雜時,手工優化會花去大量時間,而且可維護性也不高,不能保證每個人都有手工優化的能力。至此,virtual dom 的解決方案應運而生。

virtual dom 是「解決過多的操作 dom 影響性能」的一種解決方案。

virtual dom 很多時候都不是最優的操作,但它具有普適性,在效率、可維護性之間達到平衡。

virutal dom 的意義:

vue2.x 的 diff 位於 patch.js 文件中,該演算法來源於 snabbdom,復雜度為 O(n)。了解 diff 過程可以讓我們更高效的使用框架。react 的 diff 其實和 vue 的 diff 大同小異。

最大特點:比較只會在同層級進行, 不會跨層級比較。

對比之前和之後:可能期望將 直接移動到

的後邊,這是最優的操作。

但是實際的 diff 操作是:

vue 中也使用 diff 演算法,有必要了解一下 Vue 是如何工作的。通過這個問題,我們可以很好的掌握,diff 演算法在整個編譯過程中,哪個環節,做了哪些操作,然後使用 diff 演算法後輸出什麼?

解釋:

mount 函數主要是獲取 template,然後進入 compileToFunctions 函數。

compileToFunction 函數主要是將 template 編譯成 render 函數。首先讀取緩存,沒有緩存就調用 compile 方法拿到 render 函數的字元串形式,在通過 new Function 的方式生成 render 函數。

compile 函數將 template 編譯成 render 函數的字元串形式。後面我們主要講解 render

完成 render 方法生成後,會進入到 mount 進行 DOM 更新。該方法核心邏輯如下:

上面提到的 compile 就是將 template 編譯成 render 函數的字元串形式。核心代碼如下:

compile 這個函數主要有三個步驟組成:

分別輸出一個包含

parse 函數:主要功能是 將 template 字元串解析成 AST(抽象語法樹) 。前面定義的 ASTElement 的數據結構,parse 函數就是將 template 里的結構(指令,屬性,標簽) 轉換為 AST 形式存進 ASTElement 中,最後解析生成 AST。

optimize 函數(src/compiler/optomizer.js):主要功能是 標記靜態節點 。後面 patch 過程中對比新舊 VNode 樹形結構做優化。被標記為 static 的節點在後面的 diff 演算法中會被直接忽略,不做詳細比較。

generate 函數(src/compiler/codegen/index.js):主要功能 根據 AST 結構拼接生成 render 函數的字元串

其中 genElement 函數(src/compiler/codgen/index.js)是根據 AST 的屬性調用不同的方法生成字元串返回。

總之:

就是 compile 函數中三個核心步驟介紹,

patch 函數 就是新舊 VNode 對比的 diff 函數,主要是為了優化 dom,通過演算法使操作 dom 的行為降低到最低, diff 演算法來源於 snabbdom,是 VDOM 思想的核心。snabbdom 的演算法是為了 DOM 操作跨級增刪節點較少的這一目標進行優化, 它只會在同層級進行,不會跨層級比較。

總的來說:

在創建 VNode 就確定類型,以及在 mount/patch 的過程中採用位運算來判斷一個 VNode 的類型,在這個優化的基礎上再配合 Diff 演算法,性能得到提升。

可以看一下 vue3.x 的源碼:https://github.com/vuejs/vue/blob//src/core/vdom/patch.js

對 oldFiber 和新的 ReactElement 節點的比對,將會生成新的 fiber 節點,同時標記上 effectTag,這些 fiber 會被連到 workInProgress 樹中,作為新的 WIP 節點。樹的結構因此被一點點地確定,而新的 workInProgress 節點也基本定型。在 diff 過後,workInProgress 節點的 beginWork 節點就完成了,接下來會進入 completeWork 階段。

snabbdom 演算法:https://github.com/snabbdom/snabbdom

定位:一個專注於簡單性、模塊化、強大功能和性能的虛擬 DOM 庫。

snabbdom 中定義 Vnode 的類型(https://github.com/snabbdom/snabbdom/blob//src/vnode.ts#L12)

init 函數的地址:

https://github.com/snabbdom/snabbdom/blob//src/init.ts#L63

init() 函數接收一個模塊數組 moles 和可選的 domApi 對象作為參數,返回一個函數,即 patch() 函數。

domApi 對象的介麵包含了很多 DOM 操作的方法。

源碼:

https://github.com/snabbdom/snabbdom/blob//src/init.ts#L367

源碼:

https://github.com/snabbdom/snabbdom/blob//src/h.ts#L33

h() 函數接收多種參數,其中必須有一個 sel 參數,作用是將節點內容掛載到該容器中,並返回一個新 VNode。

在 vue2.x 不是完全 snabbdom 演算法,而是基於 vue 的場景進行了一些修改和優化,主要體現在判斷 key 和 diff 部分。

1、在 snabbdom 中 通過 key 和 sel 就判斷是否為同一節點,那麼在 vue 中,增加了一些判斷 在滿足 key 相等的同時會判斷,tag 名稱是否一致,是否為注釋節點,是否為非同步節點,或者為 input 時候類型是否相同等。

https://github.com/vuejs/vue/blob//src/core/vdom/patch.js#L35

2、diff 差異,patchVnode 是對比模版變化的函數,可能會用到 diff 也可能直接更新。

https://github.com/vuejs/vue/blob//src/core/vdom/patch.js#L404

㈥ 你怎麼理解vue中的diff演算法

diff演算法是虛擬 DOM 的必然產物,通過新舊虛擬 DOM 對比,將變化的地方更新在真實 DOM 上,另外也需要 diff 高效的執行對比殲桐過程,從而降低時間復雜度
vue2中為了降低 watcher 力度,每個組件只有芹爛一個 watcher 與之對應,只有引入 diff 才能精確的找到發生變化的地方
diff 之所以發生變化,是引入組件數據的變化調用了 set 方法,導致 watcher能夠監控到數據的變化,導致其觸發 updateComponent 中 pathVnode方法,在 pathVnode 函數中對對比上一次渲染結果和新渲染結果.兩個節比較的過程就是發生diff的過程.整個更新過程叫做 path 過程,也叫打補丁的過程
diff 過程整體遵從深度優先,同層比較的策略;兩個節點之間比較會根據它們是否擁有子節點或者文本節點做不同的操作.比較兩組節點是演算法的重點.首先假設頭尾節點氏首坦相同做 4 次比較嘗試,如果這 4 中方式都沒有找到,就按照通用方式遍歷查找.查找結束在按照情況處理剩下的節點;藉助 key,通常可以精確的找到相同的節點,因此整個 path 過程是非常高效的

㈦ 面試中的網紅Vue源碼解析之虛擬DOM,你知多少呢深入解讀diff演算法

眾所周知,在前端的面試中,面試官非常愛考dom和diff演算法。比如,可能會出現在以下場景

滴滴滴,面試官發來一個面試邀請。接受邀請📞

我們都知道, key 的作用在前端的面試是一道很普遍的題目,但是呢,很多時候我們都只浮於知識的表面,而沒有去深挖其原理所在,這個時候我們的競爭力就在這被拉下了。所以呢,深入學習原理對於提升自身的核心競爭力是一個必不可少的過程。

在接下來的這篇文章中,我們將講解面試中很愛考的虛擬DOM以及其背後的diff演算法。 請認真閱讀本文~文末有學習資源免費共享!!!

虛擬DOM是用JavaScript對象描述DOM的層次結構。DOM中的一切屬性都在虛擬DOM中有對應的屬性。本質上是JS 和 DOM 之間的一個映射緩存。

要點:虛擬 DOM 是 JS 對象;虛擬 DOM 是對真實 DOM 的描述。

diff發生在虛擬DOM上。diff演算法是在新虛擬DOM和老虛擬DOM進行diff(精細化比對),實現最小量更新,最後反映到真正的DOM上。

我們前面知道diff演算法發生在虛擬DOM上,而虛擬DOM是如何實現的呢?實際上虛擬DOM是有一個個虛擬節點組成。

h函數用來產生虛擬節點(vnode)。虛擬節點有如下的屬性:
1)sel: 標簽類型,例如 p、div;
2)data: 標簽上的數據,例如 style、class、data-*;
3)children :子節點;
4) text: 文本內容;
5)elm:虛擬節點綁定的真實 DOM 節點;

通過h函數的嵌套,從而得到虛擬DOM樹。

我們編寫了一個低配版的h函數,必須傳入3個參數,重載較弱。

形態1:h('div', {}, '文字')
形態2:h('div', {}, [])
形態3:h('div', {}, h())

首先定義vnode節點,實際上就是把傳入的參數合成對象返回。

[圖片上傳失敗...(image-7a9966-1624019394657)]
然後編寫h函數,根據第三個參數的不同進行不同的響應。

當我們進行比較的過程中,我們採用的4種命中查找策略:
1)新前與舊前:命中則指針同時往後移動。
2)新後與舊後:命中則指針同時往前移動。
3)新後與舊前:命中則涉及節點移動,那麼新後指向的節點,移到 舊後之後
4)新前與舊後:命中則涉及節點移動,那麼新前指向的節點,移到 舊前之前

命中上述4種一種就不在命中判斷了,如果沒有命中,就需要循環來尋找,移動到舊前之前。直到while(新前<=新後&&舊前<=就後)不成立則完成。

如果是新節點先循環完畢,如果老節點中還有剩餘節點(舊前和舊後指針中間的節點),說明他們是要被刪除的節點。

如果是舊節點先循環完畢,說明新節點中有要插入的節點。

1.什麼是Virtual DOM 和Snabbdom
2.手寫底層源碼h函數
3.感受Vue核心演算法之diff演算法
4.snabbdom之核心h函數的工作原理

1、零基礎入門或者有一定基礎的同學、大中院校學生
2、在職從事相關工作1-2年以及打算轉行前端的朋友
3、對前端開發有興趣人群

㈧ 為什麼學習Vue框架

vue框架算是最近前端開發很好的工具。可以突破以前所沒有實時更新頁面。很有發展前景,很多大公司現在正在使用。

Vue框架誕生於2014年,其作者為中國人——尤雨溪,也是新人最容易入手的框架之一,不同於React和Angular,其中文文檔也便於大家閱讀和學習。Vue用於構建互動式的Web界面的庫,是一個構建數據驅動的Web界面漸進式框架,該框架遵循CMD規范,並且提供的設計模式為MVVM模式(Model->View->View-Model)和一個可組合的組合型組件系統,具有簡單的、靈活的API(介面)。該框架繼承了React的虛擬DOM技術和Angular的雙向數據綁定技術,是一款較新的功能性框架。

在這里介紹下什麼是虛擬DOM和雙向數據綁定:
1、虛擬DOM(Virtual DOM),顧名思義,從字面上理解就是虛構的DOM樹,當我們用傳統的原生API或者jQuery去操作DOM時,瀏覽器會從構建DOM樹開始從頭到尾執行一遍流程。即使計算機硬體一直在更新迭代,但是操作真實DOM的代價仍舊很昂貴,真實的DOM節點,哪怕是一個最簡單的div也包含很多屬性,所以頻繁的操作,會導致頁面卡頓,影響用戶的體驗。為了解決這個瀏覽器性能問題,虛擬DOM(Virtual DOM)就被設計出來了,其核心演算法是Diff演算法。它會將一次操作過程中對真實DOM所有更新的diff內容保存到本地的一個js對象中,最終將這個js對象一次性attach到DOM樹上,通知瀏覽器去執行繪制工作,避免了大量的無謂的計算量。

用js對象模擬DOM節點的好處是:頁面的更新可以先全部反應在js對象上,操作內存中的js對象的速度明顯要快的多。等更新完成後,在將最終的js對象映射成真實的DOM,交由瀏覽器去繪制。(提高了性能,並且運行速度快)

2、雙向數據綁定,在講雙向數據綁定前,我們要想說下單向數據綁定,單向數據綁定,就是把Model綁定到View上,當我們用JavaScript代碼更新Model時,View就會自動更新了(Model-->View)。那麼雙向數據綁定就是,用戶更新了View,Model的數據也會自動被更新(Model<-->View)。什麼情況下用戶可以更新View呢?舉個最直接的例子,填寫表單,當用戶填寫表單時,View的狀態就被更新了,如果此時MVVM框架可以自動更新Model的狀態,那麼就相當於我們把Model和View做了雙向數據綁定。其原理是我們要對input進行value 的屬性綁定(v-bind:value=」...」)將Model中的變數綁定到View上(Model->View)以及當用戶對input進行操作時,進行事件監聽(v-on:input=」...」)將View上的更新傳回Model中(View->Model)從而實現雙向數據綁定,在Vue中,以上操作過於繁瑣,便提供了v-model直接實現雙向數據綁定的效果。
在進行Vue項目開發過程中,我們可以通過script標簽引入式寫法來引入vue或者是nodejs自帶的包管理工具npm安裝vue。並且通過new Vue()進行新建一個Vue的實例對象,其下有很多屬性,包括el、data、methods、computed、watch等等,el為指向頁面的節點元素,data存儲數據,數據類型包括simple datatype(簡單數據類型)以及complex datatype(復雜數據類型),用插值表達式{{}}顯示,在插值顯示的時候,不需要寫上data,methods內存儲方法,通過fn()的形式調用方法,computed內存儲也是方法,但是其為計算數據,復雜邏輯的應該存儲在computed中,計算屬性是基於它們的依賴進行緩存的,由於computed帶有一層緩存,所以只有在它的相關依賴發生改變時才會重新運行,而methods則是調用一次生成一次,computed中的方法調用時不需要加()的,watch為監聽,監控,監聽data中的屬性值也可以監控對象,存在兩個參數(currentValue當前值和prevValue之前值)。

㈨ vue-diff演算法

渲染真實DOM的開銷是很大的,輕微的操作都可能導致頁面重新排版,非常耗性能。 相對於DOM對象,js對象處理起來更快,而且更簡單。 通過diff演算法對比新舊vdom之間的差異,可以批量的、最小化的執行 dom操作,從而提高性能。

常規:O(n^3) 遍歷樹1; 遍歷樹2; 排序; 1000個節點,十億的量級。

vue diff:O(n) 只比較同一層級 ;tag不相同,直接刪掉重建; 通過key來標識區分相同節點。

舊節點:A、B、C、D
新節點:A、E、B、C、D

1.1 兩個節點key是否相同(兩個key都沒有,即 undefined === undefined)

1.2 兩個節點tag標簽名是否一樣

1.3 兩個節點是否都為注釋節點

1.4 兩個節點的data isDef是否都相等(isDef:data !== undefined && data !== null)

1.5 兩個節點的input類型是否相同

1.6 節點a是否為非同步佔位

1.7 兩個節點的非同步函數是否相等

1.8節點b非同步函數的error是否為空(isUndef:data === undefined && data === null)

2.1 新舊節點都有子節點,調用updateChildren重春握排子節點

2.2 只有新節點有子節點,調用addVnodes添加子節點

2.3 只有舊節點有子節點,調用removeVnodes移除子節點

2.4 如果是文本節點,調用setTextContent更新節點文本內容

3.1.1 舊頭不存在,將舊頭游標往後移一位

3.1.2 舊尾不存在,將舊尾游標往前移一位

3.1.3 舊頭、新頭相同,更新節點,並將頭部游標往後移一位

3.1.4 舊尾、新尾相同,更新節點,並將尾部游標往前移一位

3.1.5 舊頭、洞爛新尾相同,更新節點,並且將舊頭移到尾部,舊頭游標往納森漏後移一位,新尾游標往前移一位

3.1.6 舊尾、新頭相同,更新節點,並且將舊尾移到頭部,新頭游標往後移一位,舊尾游標往前移一位

3.1.7 拿新頭遍歷舊子節點,找不到則新建一個節點;找到判斷節點是否相同,相同則更新節點,移動老節點,不同則新建一個節點

3.2.1 舊子節點先遍歷完畢,說明有新增節點,批量增加

3.2.2 新子節點先遍歷完畢,說明有節點刪除,批量移除

㈩ Vue中使用Sortable

之前開發一個後台管理系統,裡面用到了 Vue 和 Element-UI 這個組件庫,遇到一個挺有意思的問題,和大家分享一下。

場景是這樣,在一個列表展示爛配亮頁上,我使用了 Element-UI 的表格組件,新的需求是在原表格的基礎上賣旅支持拖拽排序。但是原有的組件本身不支持拖拽排序,而且由於是直接引入的 Element-UI ,不方便修改它的源碼,所以比較可行的方法只能是 直接操作DOM

具體的做法是在 mounted 生命周期函數里,對 this.$el 進行真實DOM的操作,監聽 drag 的一系列事件,在事件回調里移動DOM,並更新data。

HTML5 Drag 事件還是挺多的,和 Touch 事件差不多,自己手工實現也可以,不過這里就偷了個懶,直接用了一個開源的 Sortable 庫,直接傳入 this.$el ,監聽封裝後的回調,並且根據Vue的開發模式,在移動DOM的回調里更新實際的Data數據, 保持數據和DOM的一致性

如果你以為到這就結束了,那就大錯特錯,偷過的懶遲早要還。。。本以為這個方案是很美好的,沒想到剛想調試一下,就出現了詭異的現象:A和B拖拽交換位置之後,B和A又神奇得換回去了!這是怎麼回事?似乎我們的操作沒有什麼問題,在真實DOM移動了之後,我們也移動了相應的 data ,數據數組的順序和渲染出DOM的順序應該是一致的。

問題出在哪裡?我們回憶一下Vue的實現原理,在Vue2.0之前是通過 defineProperty 依賴注入和跟蹤的方式實現雙向綁定。針對v-for數組指令,如果指定了唯一的Key,則會通過高效的Diff演算法計算出數組內元素的差異,進行最少的移動或刪除操作。而Vue2.0之後在引入了 Virtual Dom 之後, Children 元素的 Dom Diff 演算法和前者其實是相似的,唯一的區別就是,2.0之前Diff直接針對 v-for 指令的數組對象,2.0之後則針對 Virtual Dom 。DOM Diff演算法在這里不再贅述,這里解釋的比較清楚 virtual-dom diff演算法

假設我們的列表元素數組是

渲染出來後的DOM節點是

那麼Virtual Dom對應的結構就是

假設拖拽排序之後,真實的DOM變為

此時我們只操作了真實DOM,改編了它的位置,而Virtual Dom的結構並沒有改變,依然是

此時我們把列表元素也按照真實DOM排序後變成

這時候根據Diff演算法,計算出的Patch為, VNode前兩項是同類型的節點 ,所以直接更新,即把$A節點飢寬更新成$B,把$B節點更新成$A,真實DOM又變回了

所以就出現了拖拽之後又被Patch演算法更新了一次的問題,操作路徑可以簡單理解為

根本原因是 Virtual DOM 和 真實DOM 之間出現了不一致。
所以在Vue2.0以前,因為沒有引入 Virtual DOM ,這個問題是不存在的。
在使用Vue框架的時候要盡量避免直接操作DOM

3.暴力解決!不走patch更新,通過v-if設置,直接重新渲染一遍。當然不建議這么做,只是提供這種思路~

所以,我們平時在使用框架的時候,也要去了解框架的實現原理的,否則遇到一些棘手的情況就會無從下手~

熱點內容
密碼修改在哪裡改 發布:2025-04-23 11:46:48 瀏覽:787
楚稅通裡面登陸的密碼是設置什麼 發布:2025-04-23 11:43:34 瀏覽:116
復利系統源碼 發布:2025-04-23 11:43:33 瀏覽:250
python微信公眾號開發教程 發布:2025-04-23 11:32:22 瀏覽:427
管理資料庫的工具 發布:2025-04-23 11:30:08 瀏覽:649
存儲proc 發布:2025-04-23 11:25:53 瀏覽:732
內存晶元和存儲晶元 發布:2025-04-23 11:08:51 瀏覽:891
風變編程案例 發布:2025-04-23 10:57:52 瀏覽:136
子彈掛件編程 發布:2025-04-23 10:52:27 瀏覽:957
學生信息錄入c語言 發布:2025-04-23 10:50:26 瀏覽:1000