目 录CONTENT

文章目录

vue框架中的key详解

Administrator
2021-11-18 / 0 评论 / 2 点赞 / 5351 阅读 / 7065 字 / 正在检测是否收录...

vue框架中的key详解

在之前进行列表渲染的时候,还有现在进行过渡动画的时候,我们在里面都看到了一个key。之前给同学样去给同学样讲解key的时候,这个东西不能重复,所以我们一般都会使用索引来进行

不推荐使用index做key

如果执行是静态渲染,则使用index做为key无可厚非,如果执行的是动态的渲染,则index千万不能做为key,否则vue内部的状态机就容易出错

<body>
    <div id="app">
        <ul>
            <li v-for="(item,index) in stuList" :key="index">
                学号:{{item.sid}}---姓名:{{item.sname}}
            </li>
        </ul>
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    new Vue({
        el:"#app",
        data:{
            stuList:[
                {sid:"H1001",sname:"张珊"},
                {sid:"H1002",sname:"李四"},
                {sid:"H1003",sname:"王五"},
            ]
        }
    })
</script>

这就是一个表态渲染,因为数组stuList后面不会发生改变了

存在的问题

<body>
    <div id="app">
        学号:<input type="text" v-model="sid">
        姓名:<input type="text" v-model="sname">
        <button type="button" @click="addData">添加</button>
        <ul>
            <li v-for="(item,index) in stuList" :key="index">
                <input type="checkbox">
                学号:{{item.sid}}---姓名:{{item.sname}}
            </li>
        </ul>
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    new Vue({
        el: "#app",
        data: {
            sid: "",
            sname: "",
            stuList: [{
                    sid: "H1001",
                    sname: "张珊"
                },
                {
                    sid: "H1002",
                    sname: "李四"
                },
                {
                    sid: "H1003",
                    sname: "王五"
                },
            ]
        },
        methods: {
            addData() {
                this.stuList.unshift({
                    sid: this.sid,
                    sname: this.sname
                });
                this.sid = "";
                this.sname = "";
            }
        }
    })
</script>

添加数据之前

image.png

添加数据的时候

image.png

添加完成的时候

image.png

这个时候发现原本应该是“李四”这一项被钩选,结果现在变成了“张三”。原因??????

在vue的内部,vue是通过key来控制状态的,而我们在渲染的时候是通过

 <li v-for="(item,index) in stuList" :key="index">
     <input type="checkbox">
     学号:{{item.sid}}---姓名:{{item.sname}}
</li>

我们的内部使用索引做了key ,所以在变化之前,vue记住了是key为1 的这一项被钩选了,然后再下次重新渲染的时候,渲染完成以后,它还会将key为1的钩选,但是这个时候,发现key已经变了

image.png


vue在执行内部渲染的时候,使用了一种叫diff的算法,它把渲染之前和渲染之后的数据进行对比,然后只更改差异项

image.png

vue的内部是将渲染之前的数据与渲染之后的数据进行对比,这个时候对比依据就是key

它在执行对比的时候,发现每个key 都改变了,它又重新渲染了4个,但是本应该只渲染1次,上面的代码就极大的消耗了浏览器的性能,所以如果执行的是动态渲染,我们不推荐使用index做key

解决方法

<li v-for="(item,index) in stuList" :key="item.sid">
    <input type="checkbox">
    学号:{{item.sid}}---姓名:{{item.sname}}
</li>

image.png

我们现在再来看一下vue是怎么执行的内部对比

image.png

这个时候 vue在内部进行对比的时候,发现后面三项都没有变,只有前面多了一项,所以在渲染的时候也仅仅只会更改最前面的一项,这样效率非常高,也答会我们的数据驱动页面的本质

案例

<!DOCTYPE html>
<html lang="zh">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>transition中key</title>
    <style>
        .list-box {
            list-style-type: none;
            margin: 0;
            padding: 0;
            display: flex;
        }

        .list-box>li {
            width: 40px;
            height: 40px;
            background-color: lightseagreen;
            margin: 5px;
            display: flex;
            justify-content: center;
            align-items: center;
        }

        .aaa-enter {
            transform: translateY(-150%);
            opacity: 0;
        }

        .aaa-enter-to,
        .aaa-leave {
            transform: translateY(0);
            opacity: 1;
        }

        .aaa-leave-to {
            opacity: 0;
            transform: translateY(150%);
        }

        .aaa-enter-active,
        .aaa-leave-active {
            transition: all 1s linear;
        }
    </style>
</head>

<body>
    <div id="app">
        <button type="button" @click="add">+</button>
        <button type="button" @click="sub">-</button>
        <hr>
        <transition-group name="aaa" tag="ul" class="list-box">
            <li v-for="(item,index) in numList" :key="item+'aaa'">{{item}}</li>
        </transition-group>
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    new Vue({
        el: "#app",
        data: {
            numList: [0, 1, 2, 3]
        },
        methods: {
            add() {
                this.numList.push(this.numList.length);
            },
            sub() {
                let index = parseInt(Math.random() * this.numList.length);
                this.numList.splice(index, 1);
            }

        }
    })
</script>

</html>

如果我们将上面的渲染过程里在的:key="index",这样就实现不了我们的效果,因为vue在内部进行对比的时候找不到你的变化项(或者会把你的变化项判断错误)

2
vue

评论区