Vue 中的 key 有什么作用?
一、首先让我们看一下vue中的源码中key值的使用因为key值的使用主要是在diff算法中用到, 所以我们可以在vue源码的src\core\vdom\patch.js目录中可以找到相关代码来进行分析。sameVnode函数从代码上可以看到,此处 key 决定了 当前节点是否应该 patch(打补丁),所以 key不相同的话,节点将会被销毁/添加,因此会执行如下事件,执行过程中会完整...
一、首先让我们看一下vue中的源码中key值的使用
因为key值的使用主要
是在diff算法
中用到, 所以我们可以在vue源码的 src\core\vdom\patch.js
目录中可以找到相关代码来进行分析。
sameVnode
函数
从代码上可以看到,此处 key 决定了 当前节点是否应该 patch(打补丁),所以 key不相同的话,节点将会被销毁/添加,因此会执行如下事件,执行过程中会完整地触发组件的生命周期钩子并触发过渡。
function sameVnode (a, b) {
return (
a.key === b.key && (
(
a.tag === b.tag &&
a.isComment === b.isComment &&
isDef(a.data) === isDef(b.data) &&
sameInputType(a, b)
) || (
isTrue(a.isAsyncPlaceholder) &&
a.asyncFactory === b.asyncFactory &&
isUndef(b.asyncFactory.error)
)
)
)
}
Vue文档中对更新真实DOM的操作也进行了说明:
当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出。建议尽可能在使用 v-for 时提供 key,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。所以,简单列表的渲染可以不使用key
或者用数组的index
作为key
(效果等同于不带key
),这种模式下性能最高,但是并不能准确的更新列表项的状态。一旦你需要保存列表项的状态,那么就需要用使用唯一的key
用来准确的定位每一个列表项以及复用其自身的状态,而大部分情况下列表组件都有自己的状态。
不建议使用index作为key?
在中间插入一条数据
const list = [
{
id: 1,
name: 'test1',
},
{
id: 4,
name: '我是插队的那条数据',
}
{
id: 2,
name: 'test2',
},
{
id: 3,
name: 'test3',
},
]
此时更新渲染数据,通过index定义的key去进行前后数据的对比,发现
之前的数据 之后的数据
key: 0 index: 0 name: test1 key: 0 index: 0 name: test1
key: 1 index: 1 name: test2 key: 1 index: 1 name: 我是插队的那条数据
key: 2 index: 2 name: test3 key: 2 index: 2 name: test2
key: 3 index: 3 name: test3
对比发现除了第一个数据可以复用之前的之外,另外三条数据都需要重新渲染,而我想要的只是新增的那一条数据新渲染出来就行了,最好的办法是使用数组中不会变化的那一项作为key值,即使用id作为key值,。此时再来看其中发生的变化
之前的数据 之后的数据
key: 1 id: 1 index: 0 name: test1 key: 1 id: 1 index: 0 name: test1
key: 2 id: 2 index: 1 name: test2 key: 4 id: 4 index: 1 name: 我是插队的那条数据
key: 3 id: 3 index: 2 name: test3 key: 2 id: 2 index: 2 name: test2
key: 3 id: 3 index: 3 name: test3
对比发现只有一条id为4的数据数据变化了,其他都是就复用之前的。
造成这种现象的原因就是irtual DOM 使用Diff算法实现的原因:
当某一层有很多相同的节点时,也就是列表节点时,Diff算法的更新过程默认情况下也是遵循以上原则。 比如一下这个情况:
我们希望可以在B和C之间加一个F,Diff算法默认执行起来是这样的:
即把C更新成F,D更新成C,E更新成D,最后再插入E,是不是很没有效率?
所以我们需要使用key来给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点,找到正确的位置区插入新的节点。
所以概括来说key的作用主要是为了高效准确的更新虚拟DOM。另外vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让vue可以区分它们,否则vue只会替换其内部属性而不会触发过渡效果。
更多推荐
所有评论(0)