Vue v-for key值是否要设置为唯一标识?

1,750 阅读3分钟

Vue脚手架最新版eslint对vfor key值的检验比较严格,不给就报错?!Vue v-for key值到底要不要给? 给的话一定要给唯一标识吗?这里先给结论:

  • 数组元素下标不会变化,key值给index即可
  • 数组元素可能变化,key值给唯一标识

Vue渲染列表与"就地更新"策略

请看以下的例子: DOM中渲染数组,同时有一个按钮用于反转数组。

<div id="app">
    <!-- 数组反转按钮 -->
    <button @click="reverseArr">反转</button>
    <!-- 渲染数组的列表 -->
    <ul>
        <li v-for="(item, index) in songList">
            {{item.name}}
        </li>
    </ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            songList: [
                {
                    name: '无人之岛',
                    id: 1
                },
                {
                    name: '晴天',
                    id: 2
                }
            ]
        },
        methods: {
            // 反转数组
            reverseArr () {
                this.songList.reverse()
            }
        }
    })
</script>

问题:data属性数组反转到DOM渲染元素的反转,你猜Vue是如何渲染的? 两种方案:

//方案1: 不修改dom,交换dom的值
lidom0.textContent=songList[1]
lidom1.textContent=songList[0]

//方案2: 交换dom位置
parentDom = lidom0.parentNode
parentDom.insertBefore(lidom1,lidom0);

以上两种方案都可以达到渲染元素的反转,但是性能相比如何呢?操作DOM是比较耗性能的,所以方案1更优。而Vue默认用的就是第一种方案,叫做"就地更新",官方文档链接cn.vuejs.org/v2/guide/li… 为了验证这个结论,以下在渲染元素旁边放一个input框,并输入不同值,当点击按钮反转数组时,元素值交换了位置,但是input框的值并没有变

<li v-for="(item, index) in songList">
    <input/>
    {{item}}
</li>

key值设置为唯一标识总是高效吗?

  • 当点击按钮反转数组时,元素值交换了位置,但是input框的值也交换了。
  • 说明渲染列表使用了以上的方案2,也就是dom位置交换了。这是低效的渲染方式,所以有时候key值设置为唯一标识反而低效!
  • 这如何解释呢?其实给key值,Vue内部就可以区分不同li节点,以便在需要时,交换li
<li v-for="(item, index) in songList" :key="item.id">
    <input/>
    {{item}}
</li>

key值设置为index

当点击按钮反转数组时,元素值交换了位置,但是input框的值并没有变。情况和不给key效果一样。

因为当data属性数组反转后,index也变了,并不能唯一标识li,Vue内部无法根据key值来区别li节点

<li v-for="(item, index) in songList" :key="index">
    <input/>
    {{item}}
</li>

总结

其实如果key值给唯一标识总是高效的话,Vue v-for在内部实现时顺手给它所在的dom上添加一个唯一标识,比如时间戳,行不行?完全没问题。实际项目中,90%以上情况,就拿到后端返回数组,作为data属性,然后结构中v-for渲染,或者在数组末追加或删除项,所以Vue渲染时只需要在末尾追加或者删除dom,无须区分渲染节点。这个时候不给key或者key给index效果都一样。关键时这种情况占90%吧。另外如果需要在数组中间插入项时,这个时候key值给唯一标识,才会涉及虚拟DOM diff,关于这个资料一大堆,就不展开了。 知乎答主经常说一句:抛开剂量谈危害。在这里也是适用的,不能因为10%的情况下key值设置为唯一标识性能是提高的,就认为所有时候都该设置唯一标识吧。欢迎讨论。