key 的特殊 attribute 主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes。如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。而使用 key 时,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。
有相同父元素的子元素必须有独特的 key。重复的 key 会造成渲染错误。
它也可以用于强制替换元素/组件而不是重复使用它。当你遇到如下场景时它可能会很有用:
完整地触发组件的生命周期钩子
触发过渡
以上是官方说法,看完后是不是还是不明白key的作用到底是什么?
下面我们通过两个案例给大家说明下:
不同的key,组件不会复用,相同key,组件复用:
<html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Documenttitle> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script> <style> .fade-enter,.fade-leave-to{ opacity: 0; } .fade-enter-to,.fade-leave{ opacity: 1; } .fade-enter-active,.fade-leave-active{ transition: all 1s ease; }style>head><body> <div id="app"> <transition name="fade"> <item v-if="show" :title="'hello'" :key="'1'">item> <item v-if="!show" :title="'world'" :key="'2'">item> transition> <button @click="show=!show">togglebutton> div> <script> Vue.component("item", { props: ["show", "title"], template: `
{{ show }} {{title}}
`, mounted() { console.log('mounted...') }, }) let app = new Vue({ el: "#app", data: { show: true } })script>body>html>
当页面的数据发生变化时,Diff算法只会比较同一层级的节点:
如果节点类型不同,直接干掉前面的节点,再创建并插入新的节点,不会再比较这个节点以后的子节点了。
如果节点类型相同,则会重新设置该节点的属性,从而实现节点的更新。
当某一层有很多相同的节点时,也就是列表节点时,Diff算法的更新过程默认情况下也是遵循以上原则。
比如一下这个情况:
我们希望可以在B和C之间加一个F,Diff算法默认执行起来是这样的:
即把C更新成F,D更新成C,E更新成D,最后再插入E,是不是很没有效率?所以我们需要使用key来给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点,找到正确的位置区插入新的节点。
所以一句话,key的作用主要是为了高效的更新虚拟DOM。另外vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让vue可以区分它们,
示例代码:
<html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Documenttitle> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script> <style> .fade-enter,.fade-leave-to{ opacity: 0; } .fade-enter-to,.fade-leave{ opacity: 1; } .fade-enter-active,.fade-leave-active{ transition: all 1s ease; }style>head><body> <div id="app"> <transition-group tag="ul" name="fade"> <item v-for="(l,i) in list" :title="l" :key="l"> item> transition-group> <button @click="add">togglebutton> div> <script> Vue.component("item", { props: [ "title"], template: ` {{title}} `, mounted() { console.log('mounted...') }, }) let app = new Vue({ el: "#app", data: { show: true, list:['helo','world'] }, methods: { add(){ let ri = Math.floor(Math.random()*this.list.length) console.log(ri) let id = Math.random().toString(16).slice(2) this.list.splice(ri,0,id) } }, })script>body>html>
你明白了吗?