Vue面试系列之三:v-key的作用
v-key指令的作用,可以说是面试中比较常见的问题了,那么现在我们来简单了解下。1. v-key的使用场景我们先来看一段代码:<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge
v-key指令的作用,可以说是面试中比较常见的问题了,那么现在我们来简单了解下。
1. v-key的使用场景
我们先来看一段代码:
<!DOCTYPE html>
<html lang="en">
<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>Document</title>
<script src="./vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<p v-for="item in items" :key="item">
{{item}}
</p>
</div>
</body>
<script>
const app = new Vue({
el: "#app",
data: {
items: ['a', 'b', 'c', 'd', 'e']
},
mounted() {
setTimeout(() => {
// 在c的前面插入f
this.items.splice(2, 0, 'f')
}, 2000)
},
})
</script>
</html>
这段代码的作用是:循环遍历items中的元素,之后利用生命周期函数mounted()执行了一个定时函数,定时器的作用是在元素c的前面插入f;
代码执行之后,先在在浏览器中先遍历出了a,b,c,d,e五个元素,2秒之后就会在c之前插入f;
我们可以看到,这段代码中在p标签上添加了v-key指令。
接下来,我们就来分析一下,v-key在其中所起的作用。
2. 从源码层面看v-key的作用
源码地址:src\core\vdom\patch.js---updateChildren()
由于篇幅问题,我在这里只是做一个粗略的展示,有兴趣的朋友可以自己去学习。
简单说一下:updataChildren()函数是diff算法中最重要的函数,它的作用就是向下递归遍历树;diff算法则是虚拟dom的核心算法(感兴趣的朋友可以自己找资料学习,笔者已经晕倒,关于这更深层次的问题,我表示听不见,......)
言归正传;
上面提到了算法,所以,我们依据算法的执行效率来分析问题;
如果上述代码,仅仅只是循环渲染数组中的a,b,c,d,e,那么使用v-key和不使用v-key也就无任何区别,可问题是,它还执行了一个插入元素操作,此时,v-key的作用也就体现出来了;
接下来,我们就分别来讨论:
1. 不使用v-key
如果不使用v-key,此时,执行完首次渲染之后,情况会是这样的:
在执行插入操作时,因为没有使用v-key,更新算法不知道到底要更新谁,所以,它只能见到元素就更新,也就是说它会从头开始遍历更新元素,这还不是最糟糕的,那最糟糕的是什么呢?
首先,插入之前存在一个老数组[a,b,c,d,e],而插入之后,又产生了一个新数组[a,b,f,c,d,e];
old---->[a,b,c,d,e]
new--->[a,b,f,c,d,e]
其实,在执行插入操作之后,它的更新顺序是这样的:先渲染a,然后是b(这没问题),当更新渲染第三个元素时,由于老数组里面是c,而新数组是f,它会直接覆盖c,然后将f渲染出来,之后依次覆盖渲染,而对于最后一个元素e,它没有执行覆盖操作,因为老数组里没有第五个元素,那么它就会直接创建一个e,然后追加渲染出来;
那么,上面这个操作更新算法一共执行了几次呢?
其实是五次,而且还有一次创建追加操作;
2. 使用v-key
那么使用v-key指令之后,它的渲染更新是怎样的呢?
依旧是新旧数组:
old---->[a,b,c,d,e]
new--->[a,b,f,c,d,e]
此时的更新顺序是:先更新a,然后更新b(这都一样),之后的更新就会出现一些逻辑上的变化,什么变化呢?主要就是它不会再去覆盖更新f了,而是转而更新e(为什么会这样呢,其实是更新算法所决定的,其根本就是它在新老数组中会对比更新,因为新数组中突然出现一个f,更新就转而判断尾部新老数组同时存在的元素,然后将它们更新出来),之后就会更新d,c,此时老数组已经空了,所以更新停止,最后,f被创建出来,然后插入到指定位置。
那么,上面这个操作更新算法一共执行了几次呢?
其实是五次,而且还有一次创建追加操作;
3. 那么问题来了?
有朋友就会问,使用v-key和不适用v-key都执行了五次更新操作,和一次追加操作,难道它们的执行效率不一样吗?
可以肯定的是,执行效率它是不一样的。
不使用v-key:它的更新是在执行相应的覆盖操作,算法是确确实实的在执行,有时间效率和空间效率的考量;
使用v-key:它的更新则是在判断是否已经渲染过此元素,虽然有执行次数,但是算法其实是没有执行的,也就不存在时间效率和空间效率的考量,它仅仅只是执行了一个创建插入操作。
3. 结论
1. key的作用主要是为了高效的更新虚拟DOM,其原理是vue在patch过程中通过key可以精准判断两个节点是否是同一个,从而避免频繁更新不同元素,使整个patch过程更加高效,减少DOM操作量,提高性能;
2. 如果不设置key,还会在列表更新时引发一些隐蔽的bug;
3. vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让vue可以区分它们,否则vue只会替换其内部属性而不会触发过渡效果。
更多推荐
所有评论(0)