-
在使用v-for进行列表渲染时,通常会给元素或者组件绑定一个key属性。
-
官方的解释:
-
key属性主要用在Vue的虚拟DOM算法,在新旧nodes对比时辨识VNodes;
-
如果不使用key,Vue会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法;
-
而使用key时,它会基于key的变化重新排列元素顺序,并且会移除/销毁key不存在的元素;
-
1. 插入F的案例
- 这个案例是当我点击按钮时会在中间插入一个f
<template id="my-app">
<ul>
<li v-for="item in letters" :key="item">{
{item}}</li>
</ul>
<button @click="insertF">插入元素</button>
</template>
<SCript src="../js/vue.js"></SCript>
<SCript>
const App = {
template:'#my-app',
data() {
return {
letters: ['a','b','c','d']
}
},
methods: {
insertF() {
this.letters.splice(2, 0, 'f')
}
},
}
Vue.createApp(App).mount('#app')
</SCript>
-
可以确定的是,这次更新对于ul和button是不需要进行更新的,需要更新的是li列表
-
在Vue中,对于相同父元素的子元素节点并不会重新渲染整个列表
-
因为对于列表中a、b、c、d他们都是没有变化的
-
在操作真实DOM的时候,我们只需要在中间插入一个f的li即可
-
-
那么Vue中对于列表的更新究竟是如何操作的呢?
-
Vue事实上会对于有key和没有key会调用两个不同的方法
-
有key,那么就使用 patchKeyedChildren 方法
-
没有key,那么就使用 patchUnkeyedChildren 方法
-
2. Vue源码对于key的判断
3. 没有key的操作及过程
没有key的操作(Vue源码)
const patchUnkeyedChildren = (
c1: VNode[], //旧的nodes['a','b','c','d']
c2: VNodeArrayChildren, //新的nodes['a','b','f','c','d']
container: RendererElement,
anchor: RendererNode | null,
parentComponent: ComponentInternalInstance | null,
parentSuspense: SuspenseBoundary | null,
isSVG: boolean,
slotScopeIds: string[] | null,
optimized: boolean
) => {
c1 = c1 || EMPTY_ARR
c2 = c2 || EMPTY_ARR
//1.获取旧节点的长度
const oldLength = c1.length
//2.获取新节点的长度
const newLength = c2.length
//3.获取最小的那个长度 取最小的是为了数组不会越界
const commonLength = Math.min(oldLen