1 .index值不是一定不变的,如果不加key值的话,删除前面的项。后面的index可能变也可能不变,比如加个定时器的时候会变,不加定时器不会变
2 .不加key的话,更新机制的进行diff的时候是会全部比较的,比如删除第一个的话,后面的元素其实都不一样,会一项一项的比较。然后全部元素都替换,没有做到最小更新。而且里面的传的值也会变,如果这个时候你要根据里面的值删除元素的话,就会出错,尤其是加了定时器之后
3 .所以这个key值对数据改变之后的diff更新比较有很大的性能提升,或者说有了key和没有key是两种比较和更新机制
4 .使用v-for更新已渲染的元素列表时,默认采用旧地复用策略,会复用之前的元素,有的时候使用index来做为key值,其实不是特别推荐的。可能会发生变化,最好是时间戳加上一个自增的数字
5 .如果有key的话,就会根据key值去判断某个是否修改,重新渲染这一项
6 .虚拟dom的diff算法
1 .两个相同的组件产生类似的dom结构,不同的组件产生不同的dom结构
2 .同一层级的一组节点,可以通过唯一的id进行区分
3 .当一层有很多相同的节点的时候,也就是列表节点时,diff算法的更新过程默认情况是遵循以上原则
4 .如果数据的顺序被改变,Vue将不会移动DOM元素在匹配数据项的顺序,而是”就地更新“的策略。
7 .就地复用的弊端
1 .虽然很高效,但是只适合与不依赖子组件状态或者临时的dom
2 .一旦要求新加入元素的状态,就会出问题
3 .
1 .当我们想把一个f插入到b,c之间,默认是这样的
2 .一个顶一个,并不是我们想象的那样,同理,删除的时候也是这样(c->f,d-c,e-d,然后插入e)
3 .但是如果我们给他加了key值之后
4 .diff算法就可以正确的识别此节点,找到正确的位置并插入新的节点
5 .key的作用是为了更加高效的更新虚拟do'm,另外在vue中使用相同标签元素的过度切换的时候,也需要使用key属性,其目的是为了让vue区分它们,否则vueh就只会替换其内部属性而不会触发过度效果
第二波
1 .当页面的数据发生变化的时候,diff算法知乎i比较同一层级的节点
1 .如果节点类型不同,直接干掉前面的节点,在创建并插入新的节点,不会在比较这个节点以后的子节点了
2 .如果节点类型相同,重新设置该节点的属性,从而实现节点的更新
3 .所以,当某一层有很多相同的节点的时候,diff的默认是遵循第二条的
2 .对象遍历渲染的时候,是按照Object.keys()结果遍历的,所以不能保证绝对的顺序。所以最好是按照数组里面包含对象的方法来渲染,这样可以保证绝对的顺序
3 .官方文档的明确显示的部分
1 .当使用v-for更新已经渲染过的元素列表时,默认的使用”旧地复用“策略,如果数据项的顺序被改变,Vue是不会移动dom来匹配数据项的顺序,而是简单的复用此处的每个元素,并且确保他在特定索引下显示已被渲染过的元素
2 .这个模式默认是高效的,但是只适用于不依赖子组件状态或临时DOM钻港台,比如列表渲染输出
3 .为了给Vue一个提示,使他可以追踪每个节点的身份,从而重用和重新排序现有元素,这就需要为每一个项提供一个唯一的key属性
4 .注意:不添加key的性能其实更加优秀。除了想要性能或者输出非常的内容非常简单
5 .不要使用对象或者数组之类的非原始值作为v-for的key,用字符串或者整数类型的值来取代
4 .数据的这些方法会返回一个新的数据,也就是说当调用这些方法的时候需要使用新数组替换旧的数组。Vue为了使得dom元素得到最大范围的重用而实现了一些智能的,启发式的方法。也就是说,用一个含有相同元素的数据去替换原来的数据会有非常高效的操作
5 .不能检测到的变化:数组里面使用索引设置一个项时,包括对象添加新的值的时候,所以这两种情况都需要使用特定的方法。只不过是不支持常用的用法罢了,当时为什么不加个语法糖呢。。
6 .同一个元素里面v-for和v-if的优先级,v-if将运行于每一个v-for循环中,当想根据某些条件在渲染一些dom的时候,旧可以使用这个
7 . v-if当父元素 v-for当子元素
v-if中的key
1 .v-if中想要渲染多个元素的时候,可以把一个template元素当成不可见的包裹元素,并在上面使用v-if,最终的渲染结果将不会包括template元素
2 .为了尽可能高效的渲染元素,通常会复用已有元素而不是从头开始渲染,除了更快,还以一些其他的好处
1 .以下是没有key的时候
2 .input切换的时候,会保留之前填的表格
3 .
3 .添加一个key值,vue就知道这两个元素是完全不一样的,所以创建的时候直接从0开始,而不是复用
4 .但是如果其他的地方没加key,也是会复用的。所以要在合适的位置加上key
5 .v-show:带有v-show的元素始终会被渲染并保留在dom中,v-show只是简单的切换css属性display
6 .不支持template,也不支持v-else
比较v-show,v-if
1 .v-if是真正的条件渲染因为塌糊确保在切换过程中条件块内的事件监听器和子组件适当的被销毁和重建
2 .v-if也是惰性的,如果在初始渲染时条件为假,则什么都不做,直到条件第一次变为真,才会开始渲染条件块
3 .v-show:不管是什么条件,都是会被渲染,只是简单的进行css切换
4 .v-if有更高的切换开销,v-show有更高的初始渲染开销。如果需要频繁的切换,使用v-show,如果在运行时条件很少改变,则使用v-if较好
5 .
第三波,为什么加了key还是会复用呢,没有走到mounted生命周期
//父组件
<template>
<div>
<h1 @click="handleAdd">+</h1>
<h1 @click="handleRem">-</h1>
<test v-for="c in test_arr" :value="c.value" :key="c.id"/>
</div>
</template>
<script>
import test from './son/test'
export default{
data:function(){
return {
arr:[
{
id:1,
value:1
},
{
id:2,
value:2
},
{
id:3,
value:3
},
{
id:4,
value:4
},
{
id:5,
value:5
},
{
id:6,
value:6
},
{
id:7,
value:7
},
{
id:8,
value:8
},
{
id:9,
value:9
},
{
id:10,
value:10
},
{
id:11,
value:11
},
{
id:12,
value:12
},
{
id:13,
value:13
},
{
id:14,
value:15
},
{
id:15,
value:15
},
],
test_arr:[],
start:0
}
},
methods:{
handleAdd(){
this.start++
this.test_arr=this.arr.slice(this.start,this.start+3)
},
handleRem(){
this.start--
this.test_arr=this.arr.slice(this.start,this.start+3)
}
},
components:{
test,
}
}
</script>
1 .在第一次v-for中,不加key的话,如果数据改变的话,其实走的是复用的逻辑,并不走的第一次从新渲染的步骤,也就是没有新创建dom结构,仅仅是替换了元素,那么这个时候,当我想根据新传入的数据做一些操作的行为就不会触发。其实这个情况是前后数据结构一样的。那如果前后数据结构不一样,必然有新创建dom的情况,也不会触发mounted事件么?测试发现,真的是不会触发的
2 .然后我们加上了key值,现在进行数据改变,这时发现,之后每一次变化的元素,才会触发mounted事件,也就是说,如果之前是显示在第二个的元素,现在数据发生变化之后,我们是没办法知道新的第一个元素的数据,仅仅是通过mounted事件,只有新加入的元素,才会触发mounted事件
3 .那这个时候我们就需要使用一个新的生命周期函数,update。比如以下场景:当传入组件的某一个值发生了变化,导致渲染元素的高度发生了变化,而我们又恰恰想知道新的高度。这个时候就需要在updated生命周期函数里面触发,然后改变记得这个变量
4 .这里其实第一次想的还是有点问题的,新加入的元素直接就新建就可以,不需要在复用dom,重新渲染,然后在算一遍高度了。
//子组件
<template>
<div>
{{value}}
</div>
</template>
<script>
export default {
props:{
value:{
type:Number,
}
},
mounted(){
console.log('加载了一次')
console.log(this.value)
}
}
</script>
总结
1 .key的作用是用来对比组件自身新旧DOM进行更新的,跟踪节点身份
2 .key的作用是辅助判断新旧vdom节点在逻辑上是不是同一对象。
3 .默认行为性能上会有提升?建议尽可能在使用 v-for 时提供 key attribute,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。官网文档
4 .