html列表中的key屬性有什么用

這篇文章給大家分享的是有關(guān)html列表中的key屬性有什么用的內(nèi)容。小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過來看看吧。

創(chuàng)新互聯(lián)服務(wù)項(xiàng)目包括門源網(wǎng)站建設(shè)、門源網(wǎng)站制作、門源網(wǎng)頁制作以及門源網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,門源網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到門源省份的部分城市,未來相信會繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!

diff 算法的時(shí)間復(fù)雜度是 O(n), 它的實(shí)現(xiàn)是基于以下兩個(gè)假設(shè):

兩個(gè) type 不同的元素生成不同的 DOM 樹;

在兩次渲染中,React 能通過 key 屬性判斷哪一個(gè)子元素保持不變;

本文內(nèi)容圍繞「假設(shè) 2」展開說明 diff 算法是怎么做到 O(n) 的時(shí)間復(fù)雜度的。

如果沒有 key 屬性

當(dāng)遍歷子元素列表的時(shí)候,React 會同時(shí)遍歷新舊子元素列表,一旦遇到兩個(gè)列表有不同的地方,就會生成一個(gè) mutation。

<ul>

  <li>Duke</li>

  <li>Villanova</li>

</ul>

<ul>

  <li>Connecticut</li>

  <li>Duke</li>

  <li>Villanova</li>

</ul>

例如,當(dāng)在子元素列表之前添加一個(gè)元素的時(shí)候,如果沒有 key 屬性,React 會同時(shí)遍歷新舊子元素?cái)?shù)組:

第一個(gè) li 標(biāo)簽有變化,更新;

第二個(gè) li 標(biāo)簽有變化,更新;

最后插入第三個(gè) li 標(biāo)簽;

這個(gè)算法的時(shí)間復(fù)雜度是 O(n),但是會導(dǎo)致很多不必要的 DOM 操作,性能低下。如果通過一種列表對比算法能避免掉不必要的 DOM 操作,就能優(yōu)化性能。

Levenshtein Distance 算法

為了使用算法優(yōu)化性能,讓我們對上面的問題做一個(gè)抽象,舊的子元素列表:

[1, 2, 3, 4, 5] 

進(jìn)行了一系列 DOM 節(jié)點(diǎn)的刪除、插入、修改的操作之后,得到新的列表:

[6, 3, 1, 2, 5, 4] 

知道了新舊的順序求最小的插入、刪除、修改操作,這是數(shù)組的最小編輯距離問題。最常見的是 Levenshtein Distance 算法。

舉一個(gè)例子:求 beaut( [公式] ) 和 ebau( [公式] ) 的最小編輯距離,其中 [公式] 是未知字符。動態(tài)規(guī)劃算法是通過拆分問題,定義問題狀態(tài)和狀態(tài)之間的關(guān)系,使得問題能夠以遞推(或者說分治)的方式去解決。定義長度為「i - 1」的字符串 str1 和長度為「j - 1」的字符串 str2 的最小編輯距離為 [公式] ,那么 beaut( [公式] )和 ebau( [公式] ) 的最小編輯記 [公式] ,[公式] 能且只能基于下面三個(gè)狀態(tài):

「狀態(tài) 1」 :beaut( [公式] ) 和 ebau 的最小編輯距離已知,記為 [公式] ;

「狀態(tài) 2」:beaut 和 ebau( [公式] ) 的最小編輯距離已知,記為 [公式] ;

「狀態(tài) 3」:beaut 和 ebau 的最小編輯距離已知,記為 [公式] ;

[公式] 和三個(gè)狀態(tài)之間的關(guān)系分別為下面三個(gè)公式:

[公式]

[公式]

[公式]

解釋一下第三個(gè)公式,在 [公式] 的情況下, [公式] ;如果 [公式] ,那么 [公式] 。那么上面三個(gè)公式值最小的那個(gè)就是 [公式] 的解。對照著下圖看,也就是 [公式] 的值可以通過其上方,左邊,左上對角線的值確定,公式如下:

[公式]

[公式]

[公式]

function minDistance(s1, s2) {

    const len1 = s1.length

    const len2 = s2.length

    let matrix = []

    for (let i = 0; i <= len1; i++) {

        // 構(gòu)造二維數(shù)組

        matrix[i] = new Array()

        for (let j = 0; j <= len2; j++) {

            // 初始化

            if (i == 0) {

                matrix[i][j] = j

            } else if (j == 0) {

                matrix[i][j] = i

            } else {

                // 進(jìn)行最小值分析

                let cost = 0

                if (s1[i - 1] != s2[j - 1]) { // 相同為0,不同置1

                    cost = 1

                }

                const temp = matrix[i - 1][j - 1] + cost

                matrix[i][j] = Math.min(matrix[i - 1][j] + 1, matrix[i][j - 1] + 1, temp)

            }

        }

    }

    return matrix[len1][len2] //返回右下角的值

}

從上面的代碼可以看出,LD 算法有兩個(gè)嵌套的 for 循環(huán),所以時(shí)間復(fù)雜度是 O(n*m),其中 n 為 str1 的長度,m 為 str2 的長度。如果采用 LD 算法,雖然能避免掉不必要的 DOM 操作,但是 diff 算法的時(shí)間復(fù)雜度就達(dá)不到線性了。

key 屬性的引入思路

直接應(yīng)用 LP 算法不能解決我們的問題。我們并不需要找到真正的最小編輯距離,而是需要找到一種算法,這個(gè)算法的時(shí)間復(fù)雜度必須是 O(n),并且能避免掉大部分的 DOM 操作,而前端的列表大部分的操作是子元素的移動。通過引入 key 屬性唯一標(biāo)識子元素,我們可以把最小編輯距離轉(zhuǎn)化成:key 屬性是對這個(gè)元素的唯一標(biāo)識,在這個(gè)條件下,求新舊子元素列表的最小插入、刪除、移動操作。這是一種啟發(fā)式算法。

舊的子元素列表:

[{ key: 1, val: 1 }, { key: 2, val: 2 }, { key: 3, val: 3 }]

新的子元素列表:

[{ key: 4, val: 4 }, { key: 1, val: 1 }, { key: 3, val: 3 }, { key: 2, val: 2 }]

React 子元素近似最小編輯距離算法

為了尋找上面兩個(gè)數(shù)組的近似最小編輯距離,React 的做法為,正向遍歷新的子元素,用新的子元素的 key 值去舊的子元素中查找,如果沒找到,就做插入;如果找到了就做移動操作;如果遇到舊的子元素在新的列表中找不到的情況,刪除舊的子元素。算法的時(shí)間復(fù)雜度是 O(n)。 舉一個(gè)例子,如下圖,上一排是舊的子元素列表,下一排是新的子元素列表:

代碼如下,正向遍歷 nextChildren:

「元素 6」: 是新增元素,新增到 index = 0 的位置;

「元素 3」: 不變;

「元素 1」: 元素 1 在原數(shù)組中的位置在元素 3 之前,所以需要移動到元素 3 的后面;

「元素 2」: 元素 2 在原數(shù)組中的位置也位于 3 之前,移動到元素 1 的后面;

「元素 5」: 不變;

「元素 4」: 移動到 5 后面;

updateChildren() {

  // find removed

  const removedNodes = findRemoved();

  var updates = [];

  var lastIndex = 0;

  var nextIndex = 0;

  var lastPlacedNode = null;

  for (const name in nextChildren) {

    var prevChild = prevChildren && prevChildren[name];

    var nextChild = nextChildren[name];

    if (prevChild === nextChild) {

      // 移動子元素

      if (prevChild._mountIndex < lastIndex) {

        updates.push({

          type: "MOVE_EXISTING",

          fromIndex: prevChild._mountIndex,

          toIndex: nextIndex,

          afterNode: afterNode

        })

      }

      lastIndex = Math.max(prevChild._mountIndex, lastIndex);

      prevChild._mountIndex = nextIndex;

    } else {

      if (prevChild) {

        lastIndex = Math.max(prevChild._mountIndex, lastIndex);

      }

      // 新增子元素

      updates.push({

        type: "INSERT_MARKUP",

        toIndex: nextIndex,

        content: nextChild

      });

    }

    nextIndex++;

    lastPlacedNode = getNativeNode(nextChild); // 獲取 nextChild 對應(yīng)的 DOM 節(jié)點(diǎn)

  }

  // 刪除

  for (const name in removedNodes) {

    updates.push({

      type: "REMOVE_NODE",

      content: null,

      fromIndex: prevChildren[name]._mountIndex,

      fromNode: removedNodes[name]

    })

  }

}

和 Vue 的比較

Vue 對子元素的 diff 的思路和 React 一樣,都引入了「key 是子元素的唯一標(biāo)識」這一先決條件。在引入這一條件后,比 React 做了更多的優(yōu)化,Vue 是從新老子元素列表的兩頭向中間遍歷,并多做了一些特殊判斷。就列表更新這一塊,Vue 的性能高于 React。而在 Fiber 架構(gòu)中,由于沒有反向指針,React 不容易做到通過雙向遍歷優(yōu)化子元素 diff 算法。

key 屬性最佳實(shí)踐

key 屬性幫助 React 識別哪些元素改變了,哪些元素是新增的,哪些被刪除了。元素列表中的元素的 key 值應(yīng)該是穩(wěn)定的,能起到唯一標(biāo)識的作用。下面列舉一些最佳實(shí)踐:

1. 使用能在子元素列表之間能唯一標(biāo)識這個(gè)子元素的字符串做為其 key 屬性。用數(shù)組的 index 做為 key 值是一種反模式,需要避免。

const todoItems = todos.map((todo) =>

  <li key={todo.id}>

    {todo.text}

  </li>

);

2. key 會傳遞信息給 React ,但不會傳遞給你的組件。如果你的組件中需要使用 key 屬性的值,請用其他屬性名顯式傳遞這個(gè)值。

const content = posts.map((post) =>

  <Post

    key={post.id}

    id={post.id}

    title={post.title} />

);

感謝各位的閱讀!關(guān)于“html列表中的key屬性有什么用”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學(xué)到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

名稱欄目:html列表中的key屬性有什么用
網(wǎng)頁網(wǎng)址:http://muchs.cn/article0/jpgeoo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站制作、App開發(fā)網(wǎng)站策劃、網(wǎng)頁設(shè)計(jì)公司外貿(mào)建站、商城網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都app開發(fā)公司