亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

一、Diff算法

在了解key的作用之前,先簡(jiǎn)單認(rèn)識(shí)一下diff算法??

diff算法的特點(diǎn)是平級(jí)比較,采用雙指針和遞歸的方式進(jìn)行逐級(jí)比較。

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

  • 頭頭對(duì)比
  • 尾尾對(duì)比
  • 頭尾對(duì)比
  • 尾頭對(duì)比
  • 亂序?qū)Ρ?,根?jù)舊節(jié)點(diǎn)會(huì)生成一個(gè)映射表(也就是map對(duì)象),用新的節(jié)點(diǎn)一個(gè)個(gè)在映射表里找,沒(méi)有的話插入,有的話移動(dòng)復(fù)用,多余的刪掉。

二、Key的作用

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

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

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

三、Key為Index

1) 圖解

如下圖,首先上面是舊節(jié)點(diǎn),下面是新節(jié)點(diǎn),新節(jié)點(diǎn)上在數(shù)組最前面新加了一個(gè)C節(jié)點(diǎn),因?yàn)閗ey是index,所以此時(shí)C的key還是0,但是文本是C,并不是A。

因?yàn)榈谝粋€(gè)新舊節(jié)點(diǎn)的key相同,所以此時(shí)會(huì)先進(jìn)入到頭頭對(duì)比中,而不會(huì)進(jìn)入到尾尾對(duì)比,在對(duì)比的過(guò)程中,會(huì)再次進(jìn)入到patchVnode方法中判斷新舊節(jié)點(diǎn)的文本是否一致,如果一致則直接復(fù)用,不一致則會(huì)對(duì)dom進(jìn)行操作,將舊節(jié)點(diǎn)文本替換成新節(jié)點(diǎn)文本node.textContent = text

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

此時(shí)因?yàn)榕f節(jié)點(diǎn)的開(kāi)始索引和結(jié)束索引相等,則會(huì)退出while循環(huán),根據(jù)判斷新舊節(jié)點(diǎn)的開(kāi)始和結(jié)束索引得出,最后一個(gè)剩余的新節(jié)點(diǎn)會(huì)插入(addVnodes)到A元素后面去。

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

2) 完整的步驟

看下一個(gè)完整的步驟:

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

四、Key為Id

1) 圖解

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

則開(kāi)始尾尾對(duì)比sameVnode(oldEndVnode, newEndVnode),此時(shí)key是一樣的,則進(jìn)入到patchVnode方法,判斷新舊節(jié)點(diǎn)的文本是否一致,一致的話,就復(fù)用原來(lái)的節(jié)點(diǎn)了

對(duì)比完第一組,此時(shí)新舊節(jié)點(diǎn)的尾索引減1,還是尾尾相等,開(kāi)始尾對(duì)比,重復(fù)上述的步驟,復(fù)用原來(lái)的舊節(jié)點(diǎn),沒(méi)有dom操作。

>

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

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

2) 完整的步驟

完整的步驟:

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

五、源碼

粘貼一下部分的Vue源碼

1)sameVnode

只會(huì)判斷key、 tag、是否有data的存在、是否是注釋節(jié)點(diǎn)、是否是相同的input type,來(lái)判斷是否可以復(fù)用這個(gè)節(jié)點(diǎn)。

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

  • 那么就要開(kāi)始對(duì)子節(jié)點(diǎn) child 進(jìn)行對(duì)比了。

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

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

如果有新 children 而沒(méi)有舊 children

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

如果有舊 children 而沒(méi)有新 children

  • 說(shuō)明是刪除 child,直接 removeVnodes 刪除舊子節(jié)點(diǎn)

如果新 vnode 是文字 vnode

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

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

六、總結(jié)

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

相關(guān)文章

  • Vue3中refs使用方法舉例

    Vue3中refs使用方法舉例

    在Vue中Refs是對(duì)DOM元素或已安裝到DOM的其他組件實(shí)例的引用,下面這篇文章主要給大家介紹了關(guān)于Vue3中refs使用的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-08-08
  • vue中手機(jī)號(hào),郵箱正則驗(yàn)證以及60s發(fā)送驗(yàn)證碼的實(shí)例

    vue中手機(jī)號(hào),郵箱正則驗(yàn)證以及60s發(fā)送驗(yàn)證碼的實(shí)例

    下面小編就為大家分享一篇vue中手機(jī)號(hào),郵箱正則驗(yàn)證以及60s發(fā)送驗(yàn)證碼的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-03-03
  • vue中echarts引入中國(guó)地圖的案例

    vue中echarts引入中國(guó)地圖的案例

    這篇文章主要介紹了vue中echarts引入中國(guó)地圖的案例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-07-07
  • vue如何統(tǒng)一樣式(reset.css與border.css)

    vue如何統(tǒng)一樣式(reset.css與border.css)

    這篇文章主要介紹了vue如何統(tǒng)一樣式(reset.css與border.css),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-05-05
  • 詳解Vue3框架的搭建及工程目錄

    詳解Vue3框架的搭建及工程目錄

    文章介紹了如何使用Node.js搭建Vue工程,并對(duì)Vue工程目錄進(jìn)行了詳細(xì)解讀,包括各種文件夾和文件的作用,此外,還講解了如何設(shè)置網(wǎng)頁(yè)標(biāo)題和全局樣式,以及如何配置路由,感興趣的朋友一起看看吧
    2025-03-03
  • elementui的el-popover修改樣式不生效的解決

    elementui的el-popover修改樣式不生效的解決

    在使用element-ui的時(shí)候,有一個(gè)常用的組件,那就是el-popover,本文就介紹一下elementui的el-popover修改樣式不生效的解決方法,感興趣的可以了解一下
    2021-06-06
  • Vue3中實(shí)現(xiàn)微信掃碼登錄的步驟和代碼示例

    Vue3中實(shí)現(xiàn)微信掃碼登錄的步驟和代碼示例

    在 Vue 3 中實(shí)現(xiàn)微信掃碼登錄,涉及到前端生成二維碼、監(jiān)聽(tīng)微信回調(diào)以及與后端的交互,本文給大家介紹了一個(gè)詳細(xì)的實(shí)現(xiàn)步驟和代碼示例,對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-07-07
  • 在Vue的mounted中仍然加載渲染不出echarts的方法問(wèn)題

    在Vue的mounted中仍然加載渲染不出echarts的方法問(wèn)題

    這篇文章主要介紹了在Vue的mounted中仍然加載渲染不出echarts的方法問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • 解決vue+webpack項(xiàng)目接口跨域出現(xiàn)的問(wèn)題

    解決vue+webpack項(xiàng)目接口跨域出現(xiàn)的問(wèn)題

    這篇文章主要介紹了解決vue+webpack項(xiàng)目接口跨域出現(xiàn)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-08-08
  • Vue+Axios實(shí)現(xiàn)文件上傳自定義進(jìn)度條

    Vue+Axios實(shí)現(xiàn)文件上傳自定義進(jìn)度條

    這篇文章主要為大家詳細(xì)介紹了Vue+Axios實(shí)現(xiàn)文件上傳自定義進(jìn)度條,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-08-08

最新評(píng)論