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

Vue中key為index和id的區(qū)別示例詳解

 更新時間:2023年06月13日 10:01:48   作者:Lakeiedward  
這篇文章主要介紹了Vue中key為index和id的區(qū)別詳解,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

一、Diff算法

在了解key的作用之前,先簡單認識一下diff算法??

diff算法的特點是平級比較,采用雙指針和遞歸的方式進行逐級比較。

Vue會有一個根節(jié)點,先判斷根節(jié)點是否是文本節(jié)點,如果不是文本節(jié)點,則會判斷是否都有兒子節(jié)點,如果都有并且新舊兒子節(jié)點不相等,此時就會比較這兩個新舊兒子節(jié)點(updateChildren),在做比較的時候會有以下幾種情況:

  • 頭頭對比
  • 尾尾對比
  • 頭尾對比
  • 尾頭對比
  • 亂序?qū)Ρ?,根?jù)舊節(jié)點會生成一個映射表(也就是map對象),用新的節(jié)點一個個在映射表里找,沒有的話插入,有的話移動復用,多余的刪掉。

二、Key的作用

在比較兩個節(jié)點的時候sameVnode(oldStartVnode, newStartVnode),主要根據(jù)key進行判斷兩個元素是否是一個元素,key不相同的話則說明不是同一個元素。使用key的時候盡量保持key的唯一性(這樣可以優(yōu)化diff算法)

動態(tài)列表添加的key的時候,要避免使用索引(index)!

接下來,我們使用數(shù)組渲染一組兒子節(jié)點小li,并且通過事件在數(shù)組的頭部增加(unshift)一個數(shù)據(jù);當key為index的時候,我們查看下圖圖片渲染的情況發(fā)現(xiàn)所有的小li都變化了,而key為id的時候,則只在li的最前面新加了一個小li,這就是diff算法根據(jù)key判斷產(chǎn)生的差異性,具體在下面來看一看。

三、Key為Index

1) 圖解

如下圖,首先上面是舊節(jié)點,下面是新節(jié)點,新節(jié)點上在數(shù)組最前面新加了一個C節(jié)點,因為key是index,所以此時C的key還是0,但是文本是C,并不是A。

因為第一個新舊節(jié)點的key相同,所以此時會先進入到頭頭對比中,而不會進入到尾尾對比,在對比的過程中,會再次進入到patchVnode方法中判斷新舊節(jié)點的文本是否一致,如果一致則直接復用,不一致則會對dom進行操作,將舊節(jié)點文本替換成新節(jié)點文本node.textContent = text

第一組對比完成之后,新舊節(jié)點的索引會依次增加,對比第二組,第二組的key也是一樣的,會重復第一組的對比方式,最后將舊節(jié)點文本替換成新節(jié)點文本node.textContent = text

此時因為舊節(jié)點的開始索引和結(jié)束索引相等,則會退出while循環(huán),根據(jù)判斷新舊節(jié)點的開始和結(jié)束索引得出,最后一個剩余的新節(jié)點會插入(addVnodes)到A元素后面去。

此時更新就結(jié)束了,會發(fā)現(xiàn)進行了三次dom操作,雖然新舊節(jié)點除了新增的C節(jié)點,其他都是相同的,但是都沒有復用原來的節(jié)點,而是直接使用textContent改變文本,所以index作為key不中!

2) 完整的步驟

看下一個完整的步驟:

  • 如果key是index,在頭部添加一個節(jié)點,新加的節(jié)點key還是0,和第一個舊節(jié)點是一樣的key(但是文本不一樣),sameVnode就會判斷他們倆是一樣的節(jié)點,就會頭頭對比(而不是尾尾對比),此時雖然key相同的了,但是會遞歸進入到patchNode中時,會判斷文本是否相同(key為index時,文本不相同),如果不相同,則會進行dom文本替換,把舊的文本替換成新的文本,就會出現(xiàn)上圖所有的小li進行更新。
  • 以上步驟會一直重復頭頭對比,雖然每次對比時,key都是一樣的,但是文本內(nèi)容不一樣,則會一直觸發(fā)dom更新操作,也就是類似lis[0].textContent = 'C',一直到循環(huán)結(jié)束oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx,此時把多的新節(jié)點添加(addVnodes)進去,或者多的老節(jié)點刪除(removeVnodes)掉。

四、Key為Id

1) 圖解

如下圖,新加的節(jié)點key為c,當進行sameVnode(oldStartVnode, newStartVnode)對比的時候,發(fā)現(xiàn)key不一樣

則開始尾尾對比sameVnode(oldEndVnode, newEndVnode),此時key是一樣的,則進入到patchVnode方法,判斷新舊節(jié)點的文本是否一致,一致的話,就復用原來的節(jié)點了

對比完第一組,此時新舊節(jié)點的尾索引減1,還是尾尾相等,開始尾對比,重復上述的步驟,復用原來的舊節(jié)點,沒有dom操作。

>

對比完第二組,舊節(jié)點的頭索引和尾索引相等,則結(jié)束while循環(huán),最后一個剩余的新節(jié)點會插入(addVnodes)到A元素前面去。

以上的步驟完成之后,只有最后一次執(zhí)行了插入dom操作,優(yōu)化了diff算法和減少了dom操作

2) 完整的步驟

完整的步驟:

  • 如果key是唯一的id,向前追加一個,sameVnode判斷新舊節(jié)點時發(fā)現(xiàn)新舊節(jié)點的key不相同,開始尾對比,尾對比會進入到patchVnode方法,當為文本節(jié)點時,判斷新舊節(jié)點的文本是否相同,結(jié)果發(fā)現(xiàn)相同,則不做更新dom操作,直接復用原來的,一直到循環(huán)結(jié)束oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx,此時只需要把多的新節(jié)點添加(addVnodes)進去,或者多的老節(jié)點刪除(removeVnodes)掉即可,沒有多余的dom操作。

五、源碼

粘貼一下部分的Vue源碼

1)sameVnode

只會判斷key、 tag、是否有data的存在、是否是注釋節(jié)點、是否是相同的input type,來判斷是否可以復用這個節(jié)點。

function sameVnode(a, b) {
  return (
    a.key === b.key &&
    a.asyncFactory === b.asyncFactory &&
    ((a.tag === b.tag &&
      a.isComment === b.isComment &&
      isDef(a.data) === isDef(b.data) &&
      sameInputType(a, b)) ||
      (isTrue(a.isAsyncPlaceholder) && isUndef(b.asyncFactory.error)))
  )
}
function sameInputType(a, b) {
  if (a.tag !== 'input') return true
  let i
  const typeA = isDef((i = a.data)) && isDef((i = i.attrs)) && i.type
  const typeB = isDef((i = b.data)) && isDef((i = i.attrs)) && i.type
  return typeA === typeB || (isTextInputType(typeA) && isTextInputType(typeB))
}

2)patchVnode

如果新 vnode 不是文字 vnode

  • 那么就要開始對子節(jié)點 child 進行對比了。

如果新舊 children 都存在(都存在 li 子節(jié)點列表,進入 )

  • 那么就是 diff算法 想要考察的最核心的點了,也就是新舊節(jié)點的 diff 過程。

如果有新 children 而沒有舊 children

  • 說明是新增 child,直接 addVnodes 添加新子節(jié)點。

如果有舊 children 而沒有新 children

  • 說明是刪除 child,直接 removeVnodes 刪除舊子節(jié)點

如果新 vnode 是文字 vnode

  • 就直接調(diào)用瀏覽器的 dom api 把節(jié)點的直接替換掉文字內(nèi)容就好。
function patchVnode(
  oldVnode,
  vnode,
  insertedVnodeQueue,
  ownerArray,
  index,
  removeOnly?: any
){
  ...
  // 判斷新節(jié)點是不是text節(jié)點
  if (isUndef(vnode.text)) {
  // 不是text節(jié)點
    if (isDef(oldCh) && isDef(ch)) {
      // 老節(jié)點和新節(jié)點都有child,并且child不相等
      if (oldCh !== ch)
        updateChildren(elm, oldCh, ch, insertedVnodeQueue, removeOnly)
    } else if (isDef(ch)) {
      // 新節(jié)點有child,老節(jié)點沒有,則新增
      if (__DEV__) {
        checkDuplicateKeys(ch)
      }
      if (isDef(oldVnode.text)) nodeOps.setTextContent(elm, '')
      addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue)
    } else if (isDef(oldCh)) {
      // 老節(jié)點有child,新節(jié)點沒有,則刪除
      removeVnodes(oldCh, 0, oldCh.length - 1)
    } else if (isDef(oldVnode.text)) {
      nodeOps.setTextContent(elm, '')
    }
  } else if (oldVnode.text !== vnode.text) {
    // 是text節(jié)點并且文本不一樣,就把舊的文本替換成新的文本
    nodeOps.setTextContent(elm, vnode.text)
  }
  ...  
}

Tips: 兒子節(jié)點不是文本時,一方有兒子,一方?jīng)]有兒子(刪除、添加),兩方都有兒子,則進入diff算法對比

六、總結(jié)

  • 動態(tài)列表添加的key的時候,要避免使用索引(index)
  • 使用唯一的key可以優(yōu)化diff算法,減少更新dom的操作

相關文章

  • vue中bus的使用及踩坑解決

    vue中bus的使用及踩坑解決

    這篇文章主要為大家詳細介紹了vue中bus的相關使用以及涉及到的問題與解決,文中的示例代碼簡潔易懂,感興趣的小伙伴可以跟隨小編一起了解一下
    2023-08-08
  • vue+node實現(xiàn)圖片上傳及預覽的示例方法

    vue+node實現(xiàn)圖片上傳及預覽的示例方法

    這篇文章主要介紹了vue+node實現(xiàn)圖片上傳及預覽的示例方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-11-11
  • Vuex入門到上手教程

    Vuex入門到上手教程

    這篇文章主要介紹了Vuex入門到上手教程,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-06-06
  • vue2+elementui進行hover提示的使用

    vue2+elementui進行hover提示的使用

    本文主要介紹了vue2+elementui進行hover提示的使用,主要分為外部和內(nèi)部,具有一定的參考價值,感興趣的可以了解一下
    2021-11-11
  • 基于vue3實現(xiàn)防抖hook的示例代碼

    基于vue3實現(xiàn)防抖hook的示例代碼

    這篇文章主要為大家詳細介紹了如何基于vue3實現(xiàn)防抖hook,文中的示例代碼簡潔易懂,具有一定的參考價值,感興趣的小伙伴可以跟隨小編一起學習一下
    2025-08-08
  • 淺談Vue內(nèi)置component組件的應用場景

    淺談Vue內(nèi)置component組件的應用場景

    這篇文章主要介紹了淺談Vue內(nèi)置component組件的應用場景,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-03-03
  • Vue.js第三天學習筆記(計算屬性computed)

    Vue.js第三天學習筆記(計算屬性computed)

    這篇文章主要為大家詳細介紹了Vue.js第三天的學習筆記,vue.js計算屬性computed,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • Vue2集成Lodop插件實現(xiàn)在線打印功能

    Vue2集成Lodop插件實現(xiàn)在線打印功能

    這篇文章主要為大家詳細介紹了Vue2如何集成Lodop插件實現(xiàn)在線打印功能,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2025-03-03
  • vue實現(xiàn)內(nèi)容可滾動的彈窗效果

    vue實現(xiàn)內(nèi)容可滾動的彈窗效果

    這篇文章主要為大家詳細介紹了vue實現(xiàn)內(nèi)容可滾動的彈窗效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • vue實現(xiàn)界面滑動效果

    vue實現(xiàn)界面滑動效果

    這篇文章主要為大家詳細介紹了vue實現(xiàn)界面滑動效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-07-07

最新評論

琼海市| 佳木斯市| 吉林省| 三原县| 日喀则市| 额尔古纳市| 瓦房店市| 保定市| 郧西县| 新安县| 苍梧县| 大名县| 河南省| 青海省| 饶平县| 连平县| 石屏县| 临夏县| 鲜城| 长葛市| 洛隆县| 和顺县| 神池县| 五常市| 两当县| 盈江县| 汉中市| 宝丰县| 晋州市| 雅江县| 武川县| 巩留县| 怀宁县| 菏泽市| 拜城县| 大兴区| 湟源县| 额尔古纳市| 长泰县| 敦煌市| 汾西县|