最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解Vue2的diff算法

 更新時(shí)間:2021年01月06日 09:03:42   作者:啥都不會(huì)的前端CV獅  
這篇文章主要介紹了Vue2的diff算法的相關(guān)資料,幫助大家更好的理解和使用vue框架,感興趣的朋友可以了解下

前言

雙端比較算法是vue2.x采用的diff算法,本篇文章只是對(duì)雙端比較算法粗略的過(guò)程進(jìn)行了一下分析,具體細(xì)節(jié)還是得Vue源碼,Vue的源碼在這

過(guò)程

假設(shè)當(dāng)前有兩個(gè)數(shù)組arr1和arr2

let arr1 = [1,2,3,4,5]
let arr2 = [4,3,5,1,2]

那么其過(guò)程有五步

  1.  arr1[0] 和 arr2[0]比較
  2.  arr1[ arr1.length-1 ] 和 arr2[ arr2.length-1 ] 比較
  3.  arr1[0] 和 arr2[ arr2.length-1 ] 比較
  4.  arr1[ arr1.length-1 ] 和 arr2[0] 比較
  5.  arr2[0] 和 arr1的每個(gè)元素進(jìn)行比較

每次比較都是從數(shù)組的兩端開(kāi)始比較,如果是首位比較相等,那么比較的開(kāi)頭索引+1

如果是在末尾比較成功,那么比較的結(jié)束索引-1,當(dāng)開(kāi)頭索引大于結(jié)束索引時(shí)說(shuō)明比較已經(jīng)結(jié)束

拆解過(guò)程

let arr1 = [1,2,3,4,5]
let arr2 = [4,3,5,1,2]

let oldStartIdx = 0 
let oldEndIdx = arr1.lenght -1
let newStartIdx = 0
let newEndIdx = arr2.length -1

let oldStartVNode = arr1[oldStartIdx]   
let oldEndVNode = arr1[oldEndIdx]  
let newStartVNode = arr2[newStartIdx]  
let newEndVNode = arr2[newEndIdx]

第一輪:
 1. 1和4比較不相等
 2. 5和2比較不相等
 3. 1和2比較不相等
 4. 5和4比較不相等
 5. 4和舊數(shù)組逐一比較,和索引為3的值相等,說(shuō)明4由索引3變換位置為了0, newStartIdx++
 //比較完后,使用u_1表示比較成功的元素
 [1,2,3,u_1,5] //arr1
 [u_1,3,5,1,2] //arr2

第二輪:
 1. 1和3比較不相等
 2. 5和2比較不相等
 3. 1和2比較不相等
 4. 5和3比較不相等
 5. 3和舊數(shù)組逐一比較,和索引為2的值相等,3由索引2變換位置為了0, newStartIdx++
 //比較成功后,使用u_2表示比較成功的元素
 [1,2,u_2,u_1,5] //arr1
 [u_1,u_2,5,1,2] //arr2

第三輪: 
 1. 1和5比較不相等 
 2. 5和2比較不相等 
 3. 1和2比較不相等 
 4. 5和5比較相等,5已經(jīng)從舊數(shù)組oldEndIdx位置移動(dòng)到了newStartIdx位置,newStartIdx++, oldEndIdx-- 
 5. 第四步比較成功,進(jìn)入下一輪 
 //比較成功后,使用u_3表示比較成功的元素 
 [1,2,u_2,u_1,u_3] //arr1 
 [u_1,u_2,u_3,1,2] //arr2

第四輪: 
 1. 1和1比較相等,1已經(jīng)從舊數(shù)組oldStartIdx位置移動(dòng)到newStartIdx位置,oldStartIdx++,newStartIdx++ 
 2. 第一步比較成功,進(jìn)入下一輪 3. 第一步比較成功,進(jìn)入下一輪 
 4. 第一步比較成功,進(jìn)入下一輪 5. 第一步比較成功,進(jìn)入下一輪 
 //比較成功后,使用u_4表示比較成功的元素 
 [u_4,2,u_2,u_1,u_3] //arr1 
 [u_1,u_2,u_3,u_4,2] //arr2


第五輪: 
 1. 2和2比較相等,1已經(jīng)從舊數(shù)組oldStartIdx位置移動(dòng)到newStartIdx位置,oldStartIdx++,newStartIdx++ 
 2. 第一步比較成功,進(jìn)入下一輪 
 3. 第一步比較成功,進(jìn)入下一輪 
 4. 第一步比較成功,進(jìn)入下一輪 
 5. 第一步比較成功,進(jìn)入下一輪 
 //比較成功后,使用u_5表示比較成功的元素 
 [u_4,u_5,u_2,u_1,u_3] //arr1 
 [u_1,u_2,u_3,u_4,u_5] //arr2

用一個(gè)gif圖來(lái)表示

上代碼

function diff(prevChildren, nextChildren) {  
 let oldStartIdx = 0 //舊數(shù)組起始索引  
 let oldEndIdx = prevChildren.length - 1 //舊數(shù)組結(jié)束索引  
 let newStartIdx = 0 //新數(shù)組其實(shí)索引  
 let newEndIdx = nextChildren.length - 1 //新數(shù)組結(jié)束索引  
 
 let oldStartVNode = prevChildren[oldStartIdx]   
 let oldEndVNode = prevChildren[oldEndIdx]  
 let newStartVNode = nextChildren[newStartIdx]  
 let newEndVNode = nextChildren[newEndIdx]  
 while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {   
  if (!oldStartVNode) { 
  //undefined 時(shí)前移一位    
  oldStartVNode = prevChildren[++oldStartIdx]   
 } else if (!oldEndVNode) { 
  //undefined 時(shí)后移一位    
  oldEndVNode = prevChildren[--oldEndIdx]   
 } else if (oldStartVNode.key === newStartVNode.key ) { //1.開(kāi)始與開(kāi)始    
  oldStartVNode = prevChildren[++oldStartIdx]    
  newStartVNode = nextChildren[++newStartIdx]   
 } else if ( oldEndVNode.key === newEndVNode.key ) { //2.結(jié)束與結(jié)束     
  oldEndVNode = prevChildren[--oldEndIdx]    
  newEndVNode = nextChildren[--newEndIdx]   
 } else if (oldStartVNode.key === newEndVNode.key ) { //3.開(kāi)始與結(jié)束    
  oldStartVNode = prevChildren[++oldStartIdx]    
  newEndVNode = nextChildren[--newEndIdx]   
 } else if (oldEndVNode.key === newStartVNode.key ) { //4.結(jié)束與開(kāi)始     
  oldEndVNode = prevChildren[--oldEndIdx]    
  newStartVNode = nextChildren[++newStartIdx]   
 } else {
  //5.新數(shù)組開(kāi)頭元素和舊數(shù)組每一個(gè)元素對(duì)比    
  const idxInOld = prevChildren.findIndex((node) => {     
   if (node && node.key === newStartVNode.key) {      
   return true     
   }     
  })    
  if (idxInOld >= 0) {     
   prevChildren[idxInOld] = undefined    
  } else {     
   //newStartVNode是新元素    
  }    
  newStartVNode = nextChildren[++newStartIdx]   
 }  
 } 
}


diff([1,2,3,4,5],[4,3,5,1,2])

我們發(fā)現(xiàn),上面的算法走完后,如果新舊兩個(gè)數(shù)組只是順序變化,那么它能完美的diff出差異,但是如果新數(shù)組有新增或者刪除的時(shí)候就不行了,因此我們?cè)趙hile循環(huán)完成后需要找出新增或者刪除的元素,那怎么知道哪些是新增哪些是刪除的元素呢?

在比較的第五步,選取的新數(shù)組的第一個(gè)元素和舊數(shù)組的所有元素逐一對(duì)比,這里我們就可以得出了這個(gè)數(shù)組是否是新增,如果對(duì)比相等,那就是位置變換,否則當(dāng)前元素就是新增的,但是,while循環(huán)的條件是oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx,如果是以下情況

let arr1 = [1,2,3,4,5]
let arr2 = [1,2,3,4,5,6,7]

因?yàn)檠h(huán)條件的導(dǎo)致,這里會(huì)在5次while后就結(jié)束了,因此在數(shù)組末尾的6和7永遠(yuǎn)走不了第五步的插入條件,那如何判斷6和7是新增的呢?我們來(lái)觀察一下while循環(huán)結(jié)束后的索引

//例子1
let arr1 = [1,2,3,4,5]
let arr2 = [1,2,3,4,5,6,7]
//diff后它們的索引為
oldStartIdx = 5, oldEndIdx = 4
newStartIdx = 5, newEndIdx = 6

//例子2
let arr1 = [1,2,3,4,5]
let arr2 = [4,5,6,7,1,3,2]
//diff后它們的索引為
oldStartIdx = 3, oldEndIdx = 2
newStartIdx = 6, newEndIdx = 5

//例子3
let arr1 = [1,2,3,4,5]
let arr2 = [7,1,3,5,6,4,2]
//diff后它們的索引為
oldStartIdx = 5, oldEndIdx = 4
newStartIdx = 4, newEndIdx = 4

//例子4
let arr1 = [1,2,3,4,5]
let arr2 = [2,4,1,5,7,3,6]
//diff后它們的索引為
oldStartIdx = 3, oldEndIdx = 2
newStartIdx = 6, newEndIdx = 6

我們發(fā)現(xiàn),新增元素的索引和newStartIdx還有newEndIdx是一一對(duì)應(yīng)的

  • 例子1:newStartIdx小于newEndIdx,并且是5和6,而新增元素6對(duì)應(yīng)在arr2的索引為6,新增元素7對(duì)應(yīng)在arr2的索引為7,此時(shí)6和7都已經(jīng)越界出arr1的長(zhǎng)度范圍
  • 例子2:newStartIdx是大于newEndIdx,沒(méi)有對(duì)應(yīng)關(guān)系
  • 例子3:newStartIdx等于newEndIdx,我們發(fā)現(xiàn)arr2索引為4的元素正是新增元素6,但是6次時(shí)沒(méi)有越界出arr1的長(zhǎng)度范圍,它剛好在數(shù)組的最后一個(gè)元素
  • 例子4:newStartIdx等于newEndIdx,arr2中索引為6的值正是新增元素6

那么得出的結(jié)論就是,如果在while循環(huán)結(jié)束后,如果newStartIdx是小于或者等于newEndIdx,那么在newStartIdx和newEndIdx索引之間對(duì)應(yīng)的元素就是新增的元素,并且oldStartIdx總是比oldEndIdx大

上面說(shuō)完了新增,那如果是刪除元素呢?看例子

//例子1
let arr1 = [4,3,5,6,7,2,1]
let arr2 = [1,3,5,4,2]
//diff后它們的索引為
oldStartIdx = 3, oldEndIdx = 4
newStartIdx = 3, newStartIdx = 2

//例子2
let arr1 = [7,2,3,5,6,1,4]
let arr2 = [5,1,2,3,4]
//diff后它們的索引為
oldStartIdx = 0, oldEndIdx = 4
newStartIdx = 4, newStartIdx = 3

//例子3
let arr1 = [1,5,4,2,6,7,3]
let arr2 = [4,5,1,2,3]
//diff后它們的索引為
oldStartIdx = 4, oldEndIdx = 5
newStartIdx = 4, newStartIdx = 3

同理新增的觀察套路,發(fā)現(xiàn)newStartIdx總是比newStartIdx大,并且需要?jiǎng)h除的元素總是在oldStartIdx和oldEndIdx對(duì)應(yīng)的索引之間,那么我們只需要把oldStartIdx和oldEndIdx的元素刪除即可,那問(wèn)題來(lái)了,像例子2 中oldStartIdx和oldEndIdx索引之間的元素有7,2,3,5,6其中真正需要?jiǎng)h除的只有7和6,這樣子不就誤刪了2,3,5么?關(guān)鍵的來(lái)了,我們看例子2的2,3,5發(fā)現(xiàn)它們走的都是雙端比較算法的第五步,第五步寫(xiě)的代碼是

 const idxInOld = prevChildren.findIndex((node) => {     
  if (node && node.key === newStartVNode.key) {      
   return true     
  }     
 })    
 if (idxInOld >= 0) {     
  prevChildren[idxInOld] = undefined    
 } else {     
 //newStartVNode是新元素    
 }    
 newStartVNode = nextChildren[++newStartIdx]

如果idxInOld>0說(shuō)明在舊數(shù)組中找到了,那么我們將preChildren[idxInOld]設(shè)置為undefined,也就是說(shuō)2,3,5經(jīng)過(guò)diff算法后,它們?cè)赼rr1中的值已經(jīng)被替換為了undefined,這里也是就為什么在diff算法開(kāi)始需要判斷!oldStartVNode和!oldEndVnode的原因了,下面我們完善代碼

function diff(prevChildren, nextChildren) { 
 let oldStartIdx = 0 //舊數(shù)組起始索引 
 let oldEndIdx = prevChildren.length - 1 //舊數(shù)組結(jié)束索引 
 let newStartIdx = 0 //新數(shù)組其實(shí)索引 
 let newEndIdx = nextChildren.length - 1 //新數(shù)組結(jié)束索引 

 let oldStartVNode = prevChildren[oldStartIdx]  
 let oldEndVNode = prevChildren[oldEndIdx] 
 let newStartVNode = nextChildren[newStartIdx] 
 let newEndVNode = nextChildren[newEndIdx] 
 while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {  
  if (!oldStartVNode) { //undefined 時(shí)前移一位   
   oldStartVNode = prevChildren[++oldStartIdx]  
  } else if (!oldEndVNode) { 
   //undefined 時(shí)后移一位   
   oldEndVNode = prevChildren[--oldEndIdx]  
  } else if (oldStartVNode.key === newStartVNode.key ) { //1.開(kāi)始與開(kāi)始   
   oldStartVNode = prevChildren[++oldStartIdx]   
   newStartVNode = nextChildren[++newStartIdx]  
  } else if ( oldEndVNode.key === newEndVNode.key ) { //2.結(jié)束與結(jié)束    
   oldEndVNode = prevChildren[--oldEndIdx]   
   newEndVNode = nextChildren[--newEndIdx]  
  } else if (oldStartVNode.key === newEndVNode.key ) { //3.開(kāi)始與結(jié)束   
   oldStartVNode = prevChildren[++oldStartIdx]   
   newEndVNode = nextChildren[--newEndIdx]  
  } else if (oldEndVNode.key === newStartVNode.key ) { //4.結(jié)束與開(kāi)始    
   oldEndVNode = prevChildren[--oldEndIdx]   
   newStartVNode = nextChildren[++newStartIdx]  
  } else {   
    //5.新數(shù)組開(kāi)頭元素和舊數(shù)組每一個(gè)元素對(duì)比   
   const idxInOld = prevChildren.findIndex((node) => {    
    if (node && node.key === newStartVNode.key) {     
     return true    
    }    
   })   
   if (idxInOld >= 0) {    
    prevChildren[idxInOld] = undefined   
   } else {    
    //newStartVNode是新元素   
   }   
   newStartVNode = nextChildren[++newStartIdx]  
  } 
 } 
 if (oldStartIdx > oldEndIdx) {    
 for (; newStartIdx <= newEndIdx; ++newStartIdx) {   
 //新增內(nèi)容   
 let vnode = nextChildren[newStartIdx]   
 } 
 } else if (newStartIdx > newEndIdx) {  
  for (let i = oldStartIdx; i <= oldEndIdx; i++) {   /
   /刪除內(nèi)容  
 } 
 }
}

diff([1,2,3,4,5],[4,3,5,1,2])

接下來(lái)我們使用兩個(gè)gif圖來(lái)表示一下diff過(guò)程

1.新增元素

2.減少元素

以上就是詳解Vue2的diff算法的詳細(xì)內(nèi)容,更多關(guān)于Vue2的diff算法的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • vue實(shí)現(xiàn)主題切換的多種思路分享

    vue實(shí)現(xiàn)主題切換的多種思路分享

    最近一段時(shí)間,一直在做主題方面的工作。我們的主題,并不是簡(jiǎn)單切換一下顏色,或者排版變化這些,而是變化比較大的主題。比如說(shuō):主題1和主題2看起來(lái)完全不一樣,功能甚至都不一樣。這樣,通過(guò)切換css就無(wú)法做到了,因此我思考良久,使用了如下2種方法
    2021-06-06
  • 在vue項(xiàng)目中使用axios發(fā)送post請(qǐng)求出現(xiàn)400錯(cuò)誤的解決

    在vue項(xiàng)目中使用axios發(fā)送post請(qǐng)求出現(xiàn)400錯(cuò)誤的解決

    這篇文章主要介紹了在vue項(xiàng)目中使用axios發(fā)送post請(qǐng)求出現(xiàn)400錯(cuò)誤的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • vue3+element 分片上傳與分片下載功能實(shí)現(xiàn)方法詳解

    vue3+element 分片上傳與分片下載功能實(shí)現(xiàn)方法詳解

    這篇文章主要介紹了vue3+element 分片上傳與分片下載功能實(shí)現(xiàn)方法,結(jié)合實(shí)例形式詳細(xì)分析了vue3+element 分片上傳與下載相關(guān)實(shí)現(xiàn)技巧與操作注意事項(xiàng),需要的朋友可以參考下
    2023-06-06
  • vue3?ref獲取組件實(shí)例詳細(xì)圖文教程

    vue3?ref獲取組件實(shí)例詳細(xì)圖文教程

    在Vue3中可以使用ref函數(shù)來(lái)創(chuàng)建一個(gè)響應(yīng)式的變量,通過(guò)將ref函數(shù)應(yīng)用于一個(gè)組件實(shí)例,我們可以獲取到該組件的實(shí)例對(duì)象,這篇文章主要給大家介紹了關(guān)于vue3?ref獲取組件實(shí)例的詳細(xì)圖文教程,需要的朋友可以參考下
    2023-10-10
  • vue如何自定義組件v-model

    vue如何自定義組件v-model

    這篇文章主要介紹了vue如何自定義組件v-model問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • 詳解vuejs中執(zhí)行npm run dev出現(xiàn)頁(yè)面cannot GET/問(wèn)題

    詳解vuejs中執(zhí)行npm run dev出現(xiàn)頁(yè)面cannot GET/問(wèn)題

    這篇文章主要介紹了詳解vuejs中執(zhí)行npm run dev出現(xiàn)頁(yè)面cannot GET/問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • vue+element實(shí)現(xiàn)圖片上傳及裁剪功能

    vue+element實(shí)現(xiàn)圖片上傳及裁剪功能

    這篇文章主要為大家詳細(xì)介紹了vue+element實(shí)現(xiàn)圖片上傳及裁剪功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-06-06
  • vue如何通過(guò)router-link或者button跳轉(zhuǎn)到一個(gè)新的頁(yè)面

    vue如何通過(guò)router-link或者button跳轉(zhuǎn)到一個(gè)新的頁(yè)面

    這篇文章主要介紹了vue如何通過(guò)router-link或者button跳轉(zhuǎn)到一個(gè)新的頁(yè)面,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • vue實(shí)現(xiàn)將一個(gè)數(shù)組內(nèi)的相同數(shù)據(jù)進(jìn)行合并

    vue實(shí)現(xiàn)將一個(gè)數(shù)組內(nèi)的相同數(shù)據(jù)進(jìn)行合并

    今天小編就為大家分享一篇vue實(shí)現(xiàn)將一個(gè)數(shù)組內(nèi)的相同數(shù)據(jù)進(jìn)行合并,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-11-11
  • Vue-cropper 圖片裁剪的基本原理及思路講解

    Vue-cropper 圖片裁剪的基本原理及思路講解

    這篇文章主要介紹了Vue-cropper 圖片裁剪的基本原理及思路講解,本文圖文并茂給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2018-04-04

最新評(píng)論

禄丰县| 略阳县| 桦南县| 巴东县| 汉川市| 随州市| 潮州市| 平顶山市| 明水县| 沙河市| 天津市| 海丰县| 西畴县| 永年县| 浠水县| 柞水县| 化州市| 马公市| 平乐县| 绥化市| 青岛市| 广宁县| 洛川县| 江油市| 广州市| 通城县| 铁力市| 南开区| 湾仔区| 沈阳市| 杂多县| 仁化县| 西丰县| 塔河县| 楚雄市| 偃师市| 稻城县| 那坡县| 芮城县| 襄城县| 独山县|