key的作用是什么

key值得作用

  • 作用1:主要作用是更高效的更新虚拟dom,减少dom操作,提高渲染性能;
  • 作用2:管理可复用的元素
更高效的更新虚拟DOM

diff算法

  • 在使用虚拟dom更新真实dom的过程之中,会通过sameVnode方法判断新旧vnode节点是否相同,若是相同会对比其子节点与文本内容,找出最小差异进行更新;

    • function sameVnode(a, b) {
        return (
          a.key === b.key &&  // key值是否相同
          a.asyncFactory === b.asyncFactory && // 异步工厂方法
          ((a.tag === b.tag && // 标签名
            a.isComment === b.isComment && // 是否为注释节点
            isDef(a.data) === isDef(b.data) && // 是否有属性
            sameInputType(a, b)) || // 是否为input节点&type属性值是否相同
            (isTrue(a.isAsyncPlaceholder) && // 是否为异步占位符节点
             isUndef(b.asyncFactory.error)
            ))
        )
      }
      
    • 通过源码可以看出 若是元素不设置key值 a.key===undefined b.key= ==undefined 造成a.key= ==b.key会很容易被认定为同一个节点;

案例1
<ul>
   <li>A</li>
   <li>B</li>
   <li>C</li>
   <li>D</li>
   <li>E</li>
</ul>

以上是目前的真实DOM,现在要在 B元素 后面插入一个 F元素

<li>F</li>
存在key值
<template>
  <div>
    <ul>
      <li v-for='item in data' :key='item'>{{item}}</li>
    </ul>
    <el-button @click='test'>按钮</el-button>
  </div>

</template>

<script>
export default {
  data(){
    return{
        data:['A','B','C','D','E']
    }
  },
  methods:{
    test(){
      this.data=['A','B','F','C','D','E']
    },
  }
}
</script>

(1)前提:

  • 比较过程中 会生成四个指针 oldVnode的头部、oldVnode的尾部(后面称为旧前与旧后);vnode的头部、vnode的尾部(后面称为新前和新后)
  • 遍历两个列表---->遍历过程中比较顺序为 旧前-新前、旧后-新后、旧前-新后、旧后-新前;

(2)比较过程:

  • [1]oldVA 与VA为同一元素;
    • patchA;
    • 指针后移;
  • [2]oldVB与VB为同一元素;
    • patchB;
    • 指针后移;
  • [3]oldVC与VF的key值不相同,不是同一节点;
    • 指针位置不变
    • 进行旧后-新后比较;
  • [4]oldVE 与VE为同一元素;
    • patchE;
    • 指针前移;
  • [4]oldVD 与VD为同一元素;
    • patchD;
    • 指针前移;
  • [5]oldVC 与VC为同一元素
    • patchC
    • 指针前移
  • [6]旧前>旧后
    • 说明vnode元素比较多,根据vnode创建真实dom F 并插入
    • 结束
      在这里插入图片描述

(3)总结

  • 进行了一次创建,0次更新;
不存在key值
<template>
  <div>
    <ul>
      <li v-for='item in data' >{{item}}</li>
    </ul>
    <el-button @click='test'>按钮</el-button>
  </div>

</template>

<script>
export default {
  data(){
    return{
        data:['A','B','C','D','E']
    }
  },
  methods:{
    test(){
      this.data=['A','B','F','C','D','E']
    },
  }
}
</script>

(1)前提:

  • 比较过程中 会生成四个指针 oldVnode的头部、oldVnode的尾部(后面称为旧前与旧后);vnode的头部、vnode的尾部(后面称为新前和新后)
  • 遍历两个列表---->遍历过程中比较顺序为 旧前-新前、旧后-新后、旧前-新后、旧后-新前;

(2)比较过程:

  • [1]oldVA 与VA为同一元素;
    • patchA;
    • 指针后移;
  • [2]oldVB与VB为同一元素;
    • patchB;
    • 指针后移;
  • [3]oldVC与VF为同一元素;
    • patchC-需更新;
    • 指针后移;
  • [4]oldVD与VC为同一元素;
    • patchD-需更新;
    • 指针后移;
  • [5]oldVE与VD为同一元素;
    • patchE-需更新;
    • 指针后移;
  • [6]旧前>旧后
    • 说明vnode元素比较多,根据vnode创建真实dom E 并插入
    • 结束
      在这里插入图片描述

(3)总结

  • 进行1次创建,3次更新
  • 效率较有key值较低;
案例2
<!-- 更新前-->
<ul>
    <li>a</li>
    <li>b</li>
    <li>c</li>
    <li>d</li>
    <li>e</li>
    <li>f</li>
</ul>

<!--更新后-->
<ul>
    <li>b</li>
    <li>f</li>
    <li>g</li>
</ul>
存在key值
<!-- 更新前-->
<ul>
    <li key='a'>a</li>
    <li key='b'>b</li>
    <li key='c'>c</li>
    <li key='d'>d</li>
    <li key='e'>e</li>
    <li key='f'>f</li>
</ul>

<!--更新后-->
<ul>
    <li key='b'>b</li>
    <li key='f'>f</li>
    <li key='g'>g</li>
</ul>

(1)前提:

  • 比较过程中 会生成四个指针 oldVnode的头部、oldVnode的尾部(后面称为旧前与旧后);vnode的头部、vnode的尾部(后面称为新前和新后)
  • 遍历两个列表---->遍历过程中比较顺序为 旧前-新前、旧后-新后、旧前-新后、旧后-新前,若是前4种都没有命中;
    • [1]存在key值
    • [2]不存在key值

(2)比较过程

  • [1]旧前-新前、旧后-新后、旧前-新后、旧后-新前都未命中;
  • [2]通过key值找出 新前元素b 在oldVnode中的索引
    • 发现oldVnode元素b—>操作真实dom,将b元素提至旧前,当前位置置空;
    • 新前指针后移
  • [3]通过key值找出 新前元素f 在oldVnode中的索引
    • 发现oldVnode元素f—>操作真实dom,将f元素提至旧前,当前位置置空;
    • 新前指针后移;
  • [4]通过key值找出 新前元素g 在oldVnode中的索引
    • 没有找到对应索引 —> 创建新元素并将dom插入;
    • 新前指针后移;
  • [5]新前>新后
    • 删除oldVnode多余节点
    • 结束
      在这里插入图片描述
管理可复用的元素

因为Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做使 Vue 变得非常快,但是这样也不总是符合实际需求;

案例
<body>
    <div id="app">
        <span v-if="byUsername">
            <label for="username">用户账号</label>
            <input type="text" id="username" placeholder="用户账号">
        </span>
        <span v-else>
            <label for="email">用户邮箱</label>
            <input type="text" id="email" placeholder="用户邮箱">
        </span>
        <button @click="byUsername =! byUsername">切换登录方式</button>
    </div>
</body>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            byUsername: true
        }
    })
</script>
  • 问题复现
    • [1]在使用账号登录页面 输入用户账号
    • [2]点击 切换登录方式 按钮 想要使用用户邮箱登录
    • [3]虽然页面变为邮箱登录页面 但是输入框中内容并未清空
  • 原因:由于标签相同,因此vue在渲染过程种并没有创建标签,而是直接复用;
  • 解决:添加key值 表示元素不是同一元素!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值