浅聊一下
灵魂拷问:你有没有在v-for
里使用过:key = "index"
,假设有,我期望你立刻改正过来并且给我点个赞,假设没有,来都来了,顺手给我点个赞…
假设您也和我相同,在预备春招。欢迎加我微信shunwuyu,这里有几十位专心去大厂的友友能够彼此鼓舞,共享信息,模仿面试,共读源码,齐刷算法,手撕面经。来吧,友友们!
开始
在向掘友们解释为什么不能使用 :key = "index"
之前,我想我还得向你们衬托一点东西
虚拟DOM
什么是虚拟DOM呢?虚拟DOM是一个目标,没想到吧…咱们来看看Vue是如何将template模板里边的东西交给浏览器来烘托的
首要经过 compiler 将 template模板变成一个虚拟DOM,再将虚拟DOM转换成HTML,最终再交给浏览器V8引擎烘托,那么虚拟DOM是什么样的呢?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="app">
<ul id="item">
<li v-for="item in list" class="item">{{item}}</li>
</ul>
</div>
<script>
const { createApp, ref } = Vue
createApp({
setup() {
const list = ref(['vue','js','html'])
return {
list
}
}
}).mount('#app')
</script>
</body>
</html>
在这里,template模板实际上是
<ul>
<li v-for="item in list">{{item}}</li>
</ul>
经过v-for循环,烘托出来了3个li
<ul>
<li>vue<li>
<li>js<li>
<li>html<li>
</ul>
咱们的compiler会将这个模板转化成虚拟DOM
let oldDom = {
tagName = 'ul',
props:{
//存放id 和 class 等
id:'item'
},
children[
{
tagName = 'li',
props:{
class:'item'
},
children:['vue']
},
{
tagName = 'li',
props:{
class:'item'
},
children:['js']
},
{
tagName = 'li',
props:{
class:'item'
},
children:['html']
},
]
}
diff算法
给前面的比如来点刺激的,加上一个按钮和反转函数,点击按钮,list反转
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="app">
<ul>
<li v-for="item in list">{{item}}</li>
</ul>
<button @click="change">change</button>
</div>
<script>
const { createApp, ref } = Vue
createApp({
setup() {
const list = ref(['唱','跳','rap','篮球'])
const change = ()=>{
list.value.reverse()
}
const add = ()=>{
list.value.unshift('6')
}
return {
list,
change,
}
}
}).mount('#app')
</script>
</body>
</html>
点击change按钮,此时咱们的DOM更改vue又是如何来更新DOM的呢?
众所周知,回流和重绘会耗费极大的性能,而当DOM发生改变的时分会触发回流重绘(能够去看我的文章(从输入4399.com到页面烘托之间的回流和重绘),那么vue3就有一个diff算法,用来优化性能
当DOM更改,compiler会生成一个新的虚拟DOM,然后经过diff算法来生成一个补丁包,用来记载旧DOM和新DOM的差异,然后再拿到html里边进行修正,最终再交给浏览器V8进行烘托
简略介绍一下diff算法的比较规则
- 同层比较,是不是相同的结点,不相同直接废弃老DOM
- 是相同结点,比较结点上的属性,发生一个补丁包
- 持续比较下一层的子节点,选用双端对列的方式,尽量复用,发生一个补丁包
- 同上
别再写 :key = “index”
要说别写 :key = “index” ,咱们得先理解key是用来干什么的…假设没有key,那么在diff算法对新旧虚拟DOM进行比较的时分就无法比较了,你看这里有两个相同的vue,当反转顺序今后diff算法不知道哪个vue该对应哪个vue了
假设咱们用index来充任key的话来看,当咱们在头部再刺进一个结点的时分,后边的index其实是改变了的,导致diff算法在比较的时分以为他们与原虚拟DM都不相同,那么diff算法就等于没有用…
能够用随机数吗?
<li v-for="item in list" :key="Math.random()">
想出这种方法的,也是一个狠人…当然是不可的,因为在template模板更新时,会发生一个新的虚拟DOM,而这个虚拟DOM里边的key也是随机值,和原虚拟DOM里的key99.99999%是不相同的…
结尾
期望你今后再也不会写 :key = “index” 了
假设您也和我相同,在预备春招。欢迎加我微信shunwuyu,这里有几十位专心去大厂的友友能够彼此鼓舞,共享信息,模仿面试,共读源码,齐刷算法,手撕面经。来吧,友友们!