千家信息网

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

发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,这篇文章给大家分享的是有关html列表中的key属性有什么用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。diff 算法的时间复杂度是 O(n), 它的实现是基于以下两个假
千家信息网最后更新 2026年11月02日html列表中的key属性有什么用

这篇文章给大家分享的是有关html列表中的key属性有什么用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

diff 算法的时间复杂度是 O(n), 它的实现是基于以下两个假设:

两个 type 不同的元素生成不同的 DOM 树;

在两次渲染中,React 能通过 key 属性判断哪一个子元素保持不变;

本文内容围绕「假设 2」展开说明 diff 算法是怎么做到 O(n) 的时间复杂度的。

如果没有 key 属性

当遍历子元素列表的时候,React 会同时遍历新旧子元素列表,一旦遇到两个列表有不同的地方,就会生成一个 mutation。

  • Duke
  • Villanova

  • Connecticut
  • Duke
  • Villanova

例如,当在子元素列表之前添加一个元素的时候,如果没有 key 属性,React 会同时遍历新旧子元素数组:

第一个 li 标签有变化,更新;

第二个 li 标签有变化,更新;

最后插入第三个 li 标签;

这个算法的时间复杂度是 O(n),但是会导致很多不必要的 DOM 操作,性能低下。如果通过一种列表对比算法能避免掉不必要的 DOM 操作,就能优化性能。

Levenshtein Distance 算法

为了使用算法优化性能,让我们对上面的问题做一个抽象,旧的子元素列表:

[1, 2, 3, 4, 5]

进行了一系列 DOM 节点的删除、插入、修改的操作之后,得到新的列表:

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

知道了新旧的顺序求最小的插入、删除、修改操作,这是数组的最小编辑距离问题。最常见的是 Levenshtein Distance 算法。

举一个例子:求 beaut( [公式] ) 和 ebau( [公式] ) 的最小编辑距离,其中 [公式] 是未知字符。动态规划算法是通过拆分问题,定义问题状态和状态之间的关系,使得问题能够以递推(或者说分治)的方式去解决。定义长度为「i - 1」的字符串 str1 和长度为「j - 1」的字符串 str2 的最小编辑距离为 [公式] ,那么 beaut( [公式] )和 ebau( [公式] ) 的最小编辑记 [公式] ,[公式] 能且只能基于下面三个状态:

「状态 1」 :beaut( [公式] ) 和 ebau 的最小编辑距离已知,记为 [公式] ;

「状态 2」:beaut 和 ebau( [公式] ) 的最小编辑距离已知,记为 [公式] ;

「状态 3」:beaut 和 ebau 的最小编辑距离已知,记为 [公式] ;

[公式] 和三个状态之间的关系分别为下面三个公式:

[公式]

[公式]

[公式]

解释一下第三个公式,在 [公式] 的情况下, [公式] ;如果 [公式] ,那么 [公式] 。那么上面三个公式值最小的那个就是 [公式] 的解。对照着下图看,也就是 [公式] 的值可以通过其上方,左边,左上对角线的值确定,公式如下:

[公式]

[公式]

[公式]

function minDistance(s1, s2) {

const len1 = s1.length

const len2 = s2.length

let matrix = []

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

// 构造二维数组

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 {

// 进行最小值分析

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 算法有两个嵌套的 for 循环,所以时间复杂度是 O(n*m),其中 n 为 str1 的长度,m 为 str2 的长度。如果采用 LD 算法,虽然能避免掉不必要的 DOM 操作,但是 diff 算法的时间复杂度就达不到线性了。

key 属性的引入思路

直接应用 LP 算法不能解决我们的问题。我们并不需要找到真正的最小编辑距离,而是需要找到一种算法,这个算法的时间复杂度必须是 O(n),并且能避免掉大部分的 DOM 操作,而前端的列表大部分的操作是子元素的移动。通过引入 key 属性唯一标识子元素,我们可以把最小编辑距离转化成:key 属性是对这个元素的唯一标识,在这个条件下,求新旧子元素列表的最小插入、删除、移动操作。这是一种启发式算法。

旧的子元素列表:

[{ 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 子元素近似最小编辑距离算法

为了寻找上面两个数组的近似最小编辑距离,React 的做法为,正向遍历新的子元素,用新的子元素的 key 值去旧的子元素中查找,如果没找到,就做插入;如果找到了就做移动操作;如果遇到旧的子元素在新的列表中找不到的情况,删除旧的子元素。算法的时间复杂度是 O(n)。 举一个例子,如下图,上一排是旧的子元素列表,下一排是新的子元素列表:

代码如下,正向遍历 nextChildren:

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

「元素 3」: 不变;

「元素 1」: 元素 1 在原数组中的位置在元素 3 之前,所以需要移动到元素 3 的后面;

「元素 2」: 元素 2 在原数组中的位置也位于 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 对应的 DOM 节点

}

// 删除

for (const name in removedNodes) {

updates.push({

type: "REMOVE_NODE",

content: null,

fromIndex: prevChildren[name]._mountIndex,

fromNode: removedNodes[name]

})

}

}

和 Vue 的比较

Vue 对子元素的 diff 的思路和 React 一样,都引入了「key 是子元素的唯一标识」这一先决条件。在引入这一条件后,比 React 做了更多的优化,Vue 是从新老子元素列表的两头向中间遍历,并多做了一些特殊判断。就列表更新这一块,Vue 的性能高于 React。而在 Fiber 架构中,由于没有反向指针,React 不容易做到通过双向遍历优化子元素 diff 算法。

key 属性最佳实践

key 属性帮助 React 识别哪些元素改变了,哪些元素是新增的,哪些被删除了。元素列表中的元素的 key 值应该是稳定的,能起到唯一标识的作用。下面列举一些最佳实践:

1. 使用能在子元素列表之间能唯一标识这个子元素的字符串做为其 key 属性。用数组的 index 做为 key 值是一种反模式,需要避免。

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

  • {todo.text}

  • );

    2. key 会传递信息给 React ,但不会传递给你的组件。如果你的组件中需要使用 key 属性的值,请用其他属性名显式传递这个值。

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

    key={post.id}

    id={post.id}

    title={post.title} />

    );

    感谢各位的阅读!关于"html列表中的key属性有什么用"这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

    元素 公式 算法 最小 属性 复杂 复杂度 数组 时间 状态 移动 三个 问题 两个 标识 不同 字符 性能 新旧 长度 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 西安纸贵互联网科技有限公司 新华互联网科技学校 互联网科技的英文 兼蜜互联网科技 深圳期待互联网科技 新华互联网科技校企合作 滨湖区互联网智能科技产品供应 青岛中康互联网医疗科技有限公司 福州新华互联网科技学校 知乎 团飞科技与伯堂互联网服务平台 宁夏众和广鑫互联网科技有限公司 互联网经济与金融科技 未来五年的互联网科技 南博望互联网科技有限公司 高科技互联网套路 每天都有哪些好的互联网科技 21世纪互联网科技成就 宁波跨境商互联网科技有限公司 福建互联网展示科技馆设计 互联网界的黑科技 咖啡网 朗新科技与工业互联网 中资互联网科技 科技类的互联网平台 互联网科技类展会 赶超互联网科技 微信多开 恒生互联网科技业指数调整周期 互联网方面的科技前沿 数字科技和互联网金融哪个好 河南商务圈互联网科技有限公司
    0