Vue中 key的作用与原理

目录

引入

key的作用

Key的取值

不绑定key属性

Key值为index

Key值为数据唯一标识

总结


引入

当你使用过Vue时,必定会对v-for的指令非常熟悉。该指令通常用于遍历数组数据。使用v-for指令时,必定离不开key属性。你是否了解该属性,该属性的作用是什么?取值有什么?分别又有什么区别呢?本文将详细介绍Vue中key的作用与原理!

扫描二维码关注公众号,回复: 16280132 查看本文章

key的作用

当你为一个列表绑定一个key属性时,该属性会存在于虚拟的DOM中,key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据用户对应修改的新数据,来生成新的虚拟DOM。随后Vue会进行新虚拟DOM与旧虚拟DOM的差异比较。进行比较的过程可以分成两种情况:

当旧虚拟DOM中找到了与新虚拟DOM相同的key时,若虚拟DOM中内容没变, 直接使用之前的真实DOM!若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM。

当旧虚拟DOM中未找到与新虚拟DOM相同的key时,创建新的真实DOM,随后渲染到到页面。

是不是有点懵,别着急,在下面的例子中会有详细地举例!!

Key的取值

key主要有以下的三种情况,现在我们举一个小案例来分别采用如下的方式,看看具体都有什么效果以及区别是什么。

我们在页面是渲染一个人员的列表,并添加一个按钮,当点击按钮时,会在人员列表前再添加一个新成员。(为啥要在列表前,这是一个关键的点!)

不绑定key属性

当我们在编写v-for时没有添加key属性时,并没有影响到我们想要的效果。对应的实现代码以及效果图如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>key的原理</title>
        <script type="text/javascript" src="../js/vue.js"></script>
    </head>
    <body>
        <!-- 准备好一个容器-->
        <div id="root">
            <h2>人员列表</h2>
            <button @click.once="add">添加一个老刘</button>
            <ul>
                <li v-for="p of persons">
                    {
   
   {p.name}}-{
   
   {p.age}}
                </li>
            </ul>
        </div>
​
        <script type="text/javascript">
            new Vue({
                el:'#root',
                data:{
                    persons:[
                        {id:'001',name:'张三',age:18},
                        {id:'002',name:'李四',age:19},
                        {id:'003',name:'王五',age:20}
                    ]
                },
                methods: {
                    add(){
                        const p = {id:'004',name:'老刘',age:40}
                        this.persons.unshift(p)
                    }
                },
            })
        </script>
</html>

这时候可能会有同学会问,不写key属性不也能够正常地显示我们想要的效果吗?所以为何那么麻烦,多加一个key属性!其实,当你没有添加key属性时,系统会默认将绑定的key属性的值指向index。则会列表的索引,例如:{id:'001',name:'张三',age:18}的index值就为0,{id:'002',name:'李四',age:19}的index值就为1,依次类推。来为每一个li标签做标识。

Key值为index

当我们添加key属性,并将该属性的值指向为index时,具体它实现出来的效果就如上的没有添加key属性一样。但是具体的实现代码有一点小区别:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>key的原理</title>
        <script type="text/javascript" src="../js/vue.js"></script>
    </head>
    <body>
        <!-- 准备好一个容器-->
        <div id="root">
            <h2>人员列表</h2>
            <button @click.once="add">添加一个老刘</button>
            <ul>
                <!-- 绑定了key属性,并将其值指向于index -->
                <li v-for="(p,index) of persons" :key="index">
                    {
   
   {p.name}}-{
   
   {p.age}}
                </li>
            </ul>
        </div>
​
        <script type="text/javascript">
            Vue.config.productionTip = false
            new Vue({
                el:'#root',
                data:{
                    persons:[
                        {id:'001',name:'张三',age:18},
                        {id:'002',name:'李四',age:19},
                        {id:'003',name:'王五',age:20}
                    ]
                },
                methods: {
                    add(){
                        const p = {id:'004',name:'老刘',age:40}
                        this.persons.unshift(p)
                    }
                },
            })
        </script>
</html>

对应的实现和上面的相同,也是能够正确地将效果显示出来。这种写法也是比较常见的。这并没有看出什么问题。但是倘若现在我在每一个列表的后面添加一个输入框,会出现什么样的效果呢?

 <div id="root">
            <h2>人员列表</h2>
            <button @click.once="add">添加一个老刘</button>
            <ul>
                <!-- 绑定了key属性,并将其值指向于index -->
                <li v-for="(p,index) of persons" :key="index">
                    {
   
   {p.name}}-{
   
   {p.age}}
                    <!-- 增加了input输入框 -->
                    <input type="text">
                </li>
            </ul>
        </div>

通过以上的效果图我们可以很明显地看出了其出现的问题,但输入框中没有内容时,添加之后并没有什么问题。但是当我们在添加之前先将对应的内容输入到相应的输入框中后,我们会发现添加之后出现了问题。所以为何会出现这种问题呢?我们来看看下面的图形演示:

当我们把index作为key时,初始数据之后会根据数据生成虚拟的DOM,对应的li标签中的key值分别是0,1,2。当数据生成初始虚拟DOM之后,会创建新的真实DOM,随后渲染到到页面。

而当我们再添加一条数据时,会根据我们新的数据来生成新的虚拟DOM。新的虚拟DOM会与初始的也就是旧的虚拟DOM来进行对比,先找到对应相同的key值的li,若虚拟DOM中内容没变, 直接使用之前的真实DOM,若虚拟DOM中内容变了, 则生成新的真实DOM,对比发现key="0"中的内容有变化,从“张三-18”变成了“老刘-30”,随后替换掉页面中之前的真实DOM。而<input type="text">对比的结果是相同的,因此保存原本的内容。key="1"以及key="2"以此类推。而key="3"并没有在旧虚拟DOM中找到,因此创建新的真实DOM,随后渲染到到页面。

这下明白了吧!!

Key值为数据唯一标识

当我们把key属性的值赋为数据中的唯一标识时,又会出现怎么样的结果呢?我们将persons中的id值赋给key属性。具体代码如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>key的原理</title>
        <script type="text/javascript" src="../js/vue.js"></script>
    </head>
    <body>
        <!-- 准备好一个容器-->
        <div id="root">
            <h2>人员列表</h2>
            <button @click.once="add">添加一个老刘</button>
            <ul>
                <!-- 绑定了key属性,并将其值指向于p.id -->
                <li v-for="(p,index) of persons" :key="p.id">
                    {
   
   {p.name}}-{
   
   {p.age}}
                    <!-- 增加了input输入框 -->
                    <input type="text">
                </li>
            </ul>
        </div>
​
        <script type="text/javascript">
            new Vue({
                el:'#root',
                data:{
                    persons:[
                        {id:'001',name:'张三',age:18},
                        {id:'002',name:'李四',age:19},
                        {id:'003',name:'王五',age:20}
                    ]
                },
                methods: {
                    add(){
                        const p = {id:'004',name:'老刘',age:40}
                        this.persons.unshift(p)
                    }
                },
            })
        </script>
</html>

 我们可以明显地看出,若我们的key属性绑定的值为数据中的唯一标识时,我们就能够得到我们想要的结果。对应的原理图如下:

由于每一个li标签中绑定的值为id,因此当添加一个新成员时,其对应的id="004",对应的key值为004,并没有在旧的虚拟DOM中找到,因此添加到真实的DOM中并渲染在页面上。其他的就不在多解释,原理都是相同的。

总结

若使用index作为key需要考虑下载两个问题:

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

那么我们在开发的过程中该如何选择key呢?

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

猜你喜欢

转载自blog.csdn.net/weixin_51735748/article/details/132155815