Vue列表渲染中的key值的重要性

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 .
16401a8ca6f8c764.jpg

1 .当我们想把一个f插入到b,c之间,默认是这样的


16401a8ca73549bb.jpg

2 .一个顶一个,并不是我们想象的那样,同理,删除的时候也是这样(c->f,d-c,e-d,然后插入e)
3 .但是如果我们给他加了key值之后


16401a8ca6d7e50c.jpg

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 .

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,099评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,473评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,229评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,570评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,427评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,335评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,737评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,392评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,693评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,730评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,512评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,349评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,750评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,017评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,290评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,706评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,904评论 2 335

推荐阅读更多精彩内容

  • MYSQL 基础知识 1 MySQL数据库概要 2 简单MySQL环境 3 数据的存储和获取 4 MySQL基本操...
    Kingtester阅读 7,736评论 5 116
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,068评论 1 32
  • 杨帛翰,1月份,第五次,读书打卡。我读的书名是:《西顿野生动物,小说全集之,泡泡野猪。 西内华达山脉坐落在...
    杨帛翰阅读 521评论 0 0
  • 提高时间管理,一般来说有两个方向。一是提高做事的效率,二是去做更有价值的事。时间管理=事件的价值×做事的效率。 工...
    讨喜的鱼阅读 512评论 0 1