Vue中`v-for`的key选择:避免陷阱,优化性能

在日常vue项目中,我们在使用v-for时,总是习惯使用index来充当key的,这样操作虽然是很方便的,但是实际上这是存在着一定的风险的。下面我将为大家介绍一下为什么使用index充当key是不安全的。

index为key时所指向的内容是会改变的

当列表的顺序发生变化时,使用index作为 key 可能导致原先所指向的内容会发生改变。让我们通过一个示例来说明这一点。

示例

vue 复制代码
<template>
  <div>
    <button @click="shuffleItems">change</button>
    <ul>
      <li v-for="(item, index) in items" :key="index">
        {{ item.text }}
      </li>
    </ul>
  </div>
</template>

<script>
import { ref } from 'vue';

export default {
  setup() {
    const items = ref([
      { id: 1, text: 'A' },
      { id: 2, text: 'B' },
      { id: 3, text: 'C' }
    ]);

    const shuffleItems = () => {
      items.value.reverse(); 
    };

    return {
      items,
      shuffleItems
    };
  }
};
</script>

在这个示例中,我们使用 reverse 方法来简单地改变列表项的顺序。这会导致原始列表中的元素以相反的顺序重新渲染,但由于我们使用了索引作为 key,Vue 并不知道列表项的顺序变化,因此不会进行相应的移动操作,而是重新创建和销毁元素,这可能导致不必要的性能开销,并且可能会导致意外的结果,特别是在涉及动画效果时。

当点击click后可以看出,下标所表示的值就已经发生了变动。如果仍然使用下标作为key的话,就会产生点击后的效果------值会发生改变,Diff无法辨别新的VDOM和旧的VDOM了。因为 Vue 会根据 key 来确定每个节点的身份。如果改变了列表的顺序,但是索引作为 key 的话,Vue 会错误地认为是相同的节点位置变化了,就会导致以上问题。

解决方案

那么这样的话我们可以通过什么办法去解决这个问题呢。既然它需要的key是不能更改的是唯一的,那么我们可以通过提供一个唯一且稳定的标识符作为 key 来解决,这样 Vue 就能正确地识别节点,并更新 DOM。

示例

vue 复制代码
<template>
  <div>
    <button @click="shuffleItems">click</button>
    <ul>
      <li v-for="item in shuffledItems" :key="item.id">{{ item.name }}</li>
    </ul>
  </div>
</template>

<script setup>
import { ref } from 'vue';

const items = ref([
  { id: 1, name: 'A' },
  { id: 2, name: 'B' },
  { id: 3, name: 'C' }
]);
console.log('items', items.value);
const shuffledItems = ref([...items.value]);

const shuffleItems = () => {

  shuffledItems.value = shuffledItems.value.sort(() => Math.random() - 0.5);
  console.log('shuffledItems', shuffledItems.value);
};
</script>

在这个示例中,我们有一个包含三个对象的 items 数组,每个对象都有一个唯一的 id 属性。当点击按钮时,shuffleItems 方法会打乱 shuffledItems 数组的顺序。由于我们使用对象的 id 属性作为 key,Vue 可以正确地识别每个项,并且在顺序发生变化时能够正确地更新 DOM。这样做的话,即使列表的顺序发生变化,Vue 也能够正确地跟踪每个节点的标识,并且能够高效地更新 DOM,提高了性能和用户体验。

结语

我们要知道Vue 使用一种称为虚拟 DOM 的技术来管理 DOM 更新。在进行比较时,Vue 会将新旧列表的节点按照 key 进行匹配,然后根据匹配的结果确定是更新现有 DOM 元素、删除不需要的元素,还是添加新的元素。可以去看我的这篇文章解析Vue中的虚拟DOM与Diff算法:提升性能的利器 - 掘金 (juejin.cn)

总结

vue使用diff算法,需要使用key来做同级比对。如果使用数组下标作为key,有以下情况:

  • 在数组头部或中部插入或删除元素: 所有key对应的节点的值发生更改,进行重新渲染。造成性能损耗
  • 而如果使用数组中唯一值来作为key:不管是在何处插入或删除节点,其他key对应的节点的值未发生更改,只需插入或删除操作的数组节点。

综上所述,使用 index 作为 key 的风险在于,当列表发生变化时,节点的顺序改变会导致 index 所指向的内容也会发生改变,从而可能导致 Vue 无法正确识别节点的变化,进而影响 DOM 的更新。这种情况下,Vue 可能会错误地创建、销毁或更新 DOM 元素,导致不必要的性能开销和意外的结果。因此,建议在使用 v-for 渲染列表时,尽量避免使用 index 作为 key,而是使用唯一且稳定的标识符作为 key,以确保 Vue 能够正确地识别节点,并更新 DOM。

最后假如您也和我一样,在准备春招。欢迎加微信shunwuyu ,这里有几十位一心去大厂的友友可以相互鼓励,分享信息,模拟面试,共读源码,齐刷算法,手撕面经。来吧,友友们!

相关推荐
冰镇屎壳郎25 分钟前
前端安全 常见的攻击类型及防御措施
前端·安全·前端安全
2401_8576176231 分钟前
“无缝购物体验”:跨平台网上购物商城的设计与实现
java·开发语言·前端·安全·架构·php
2401_8574396940 分钟前
智慧社区电商系统:提升用户体验的界面设计
前端·javascript·php·ux
我是高手高手高高手1 小时前
ThinkPHP8多应用配置及不同域名访问不同应用的配置
linux·服务器·前端·php
小李小李不讲道理1 小时前
行动+思考 | 2024年度总结
前端·程序员·年终总结
uhakadotcom1 小时前
代码人生-精选文章周刊
前端·后端·github
苹果酱05671 小时前
Golang的文件解压技术研究与应用案例
java·vue.js·spring boot·mysql·课程设计
csdnLN1 小时前
$.ajax() 对应事件done() 、fail()、always() 的用法
前端·javascript·ajax
甜味橘阳1 小时前
echarts地图可视化展示
前端·javascript·echarts
bloxed2 小时前
前端文件下载多方式集合
前端·filedownload