Vue key的作用与原理

2024-03-24 380 0

1. vue中key的作用

1)虚拟DOM中key的作用:

key是虚拟DOM对象的标识,当状态中的数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,随后Vue进行【新的虚拟DOM】与【旧的虚拟DOM】的差异比较,比较规则如下:

A. 旧虚拟DOM中找到了与新虚拟DOM相同的key:

  • 若虚拟DOM中的内容没变,直接使用之前的真实DOM;
  •  若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM;

B. 旧虚拟DOM中未找到与新虚拟DOM相同的key:

  • 创建新的真实DOM,随后渲染到页面;

2)用index作为key可能会引发的问题

  • 若对数据进行:逆序添加,逆序删除等破坏顺序的操作,会产生没必要的真实DOM更新==>界面效果没问题,但效率低
  • 如果结构中包含输入类的DOM:会产生错误DOM更新 ==>界面有问题

3)开发中如何选择key?

  • 最好使用每条数据的唯一标识作为key,比如id,手机号,身份证号,学号等唯一值;
  • 如果不存在对数据逆序添加,逆序删除等破会顺序的操作,仅用于渲染列表用于展示,使用index作为key是没问题的。

2. 遍历时用index作为key和用唯一标识(如:id)作为key的区别

例如:以列表的形式展示一组人员信息。

<div id='root'>
    <ul>
        <li v-for="(p,index) of persons">
            {{p.name}}-{{p.age}}
        </li>
    </ul>

    <ul>
        <li v-for="(p,index) of persons" :key="index">
            {{p.name}}-{{p.age}}

        </li>
    </ul>
    <ul>
        <li v-for="(p,index) of persons" :key="p.id">
            {{p.name}}-{{p.age}}

        </li>
    </ul>
</div>
<script>
    new Vue({
        el: '#root',
        data: {
            persons: [
                { id: 1, name: '张三', age: 19 },
                { id: 2, name: '李四', age: 20 },
                { id: 3, name: '王五', age: 25 }
            ]
        }
    });
</script>

上面的示例中,不写key,以index为key,以id为key遍历数据时,得到的结果相同。由此可以看出:

  • 遍历只做数据展示用时,不写key是没有任何影响的;
  • key不会出现在真实DOM中;
  • 实际上,即使不写key,Vue在生成真实DOM时,也用到了key,默认是数据索引(index)

如果将上述示例做个修改:

<div id='root'>
    <button @click="add()">添加一个老刘</button>
    <ul>
        <li v-for="(p,index) of persons" :key="index">
            {{p.name}}-{{p.age}}
            <input type="text">
        </li>
    </ul>
    <ul>
        <li v-for="(p,index) of persons" :key="p.id">
            {{p.name}}-{{p.age}}
            <input type="text">
        </li>
    </ul>
</div>
<script>
    new Vue({
        el: '#root',
         data: {
            persons: [
                { id: 1, name: '张三', age: 19 },
                { id: 2, name: '李四', age: 20 },
                { id: 3, name: '王五', age: 25 }
            ]
        },
        methods: {
            add() {
                const p = { id: 4, name: '老刘', age: 40};
                this.persons.unshift(p);
            }
        }
    });
</script>

上面的示例,如果在每个列表后加个输入框,并在输入框输入值,点击在列表前面添加一条数据,会发现以index为key和以id为key遍历显示的结果并不相同:

以index为key的渲染结果出现了错乱。

这是因为,向列表前面插入一条数据时,会先根据新数据生成新虚拟DOM,然后Vue通过虚拟DOM对比算法比较新的虚拟DOM与旧的虚拟DOM:首先找到key都为0的虚拟节点,该节点有两个子节点,一个是文本节点,另一个是输入框节点;首先对比到的是文本节点,两个文本内容不一样,用新的文本替换掉旧的文本节点,第二个对比的是输入框节点,两个节点一样,则直接复用原来的输入框;以此类推,后面的也一样。

id作为key时:首先比较key都为004的数据,比较时发现旧的虚拟DOM中并没有key为004 的数据,则直接生成新的真实DOM;接下来比较key为001的数据,key为001的文本节点和输入框节点一样,则直接复用旧的节点,后面的也一样。

两者的区别就是以id为key时只生成了一个新的节点,其他都是直接复用的旧的节点,相对来说,效率更高,而且不会出现渲染错误的问题。

相关文章

Vue 过滤器
Vue 自定义指令
Vue 计算属性和监听属性
Vue MVVM与数据代理
Vue el与data的两种写法
vue-codemirror编辑器使用(vue3)

发布评论