vue中key使用的问题示例解析

 更新时间:2022年11月28日 15:47:12   作者:空山与新雨  
这篇文章主要为大家介绍了vue中key使用的问题示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

前言

在vue要求在遍历的时候最好加上key,在使用过程中总有些疑问,在这里做下分析

不使用key的时候vue是怎么处理的

在vue2.x文档中有如下描述

key 的特殊 attribute 主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes。如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。而使用 key 时,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。

在这段话中提到不使用key的时候,会尽量原地复用,复用的判断依据是常常在面试中被问到的sameVnode这个方法:

function sameVnode (a, b) {
  return (
    // 因为没有定义key,可以得知a.key和b.key都是undefined,进而后面的条件进行判断;
    a.key === b.key && (
      (
        a.tag === b.tag &&
        a.isComment === b.isComment &&
        isDef(a.data) === isDef(b.data) &&
        sameInputType(a, b)
      ) || (
        isTrue(a.isAsyncPlaceholder) &&
        a.asyncFactory === b.asyncFactory &&
        isUndef(b.asyncFactory.error)
      )
    )
  )
}

使用key一定能提高diff效率么

答案是并不是,可以看下面的例子

<script src="https://unpkg.com/vue@2.6.14/dist/vue.min.js"></script>
<div id="app">
  <div class="ttt" v-for="(item) in list">{{item}}</div>
  <button @click="changeData">更新</button>
</div>
<script >
  new Vue({
    el: '#app',
    data() {
      return {
        list: [1, 2, 3]
      }
    },
    mounted(){
      Array.from(document.querySelectorAll('.ttt')).forEach(item=>{
        item.dataset.mm = item.textContent;
      })
    },
    methods:{
      changeData(){
        this.list = [4, 5, 6]
      }
    }
  })
</script>

初始dom结构如下:

没有key情况下更新数组,然后DOM结构如下,可以看到dataset值没有变化,可以初步判断只是更新了div的内容

使用数组元素作为key情况下更新数组,然后DOM结构如下,可以看到dataset没有了,可以初步判断删除和创建了新的dom,很明显这样处理效率更低。

vue源码中的处理程序逻辑:
没有key的情况: updateChildren -> 判定为同类型节点(div),执行patchVnode方法 -> 再对div这个节点做updateChildren处理 -> 继续patchVnode,最后的结果就是更新文本节点内容;

if (oldVnode.text !== vnode.text) {
  nodeOps.setTextContent(elm, vnode.text)
}

有key并且key不相等: updateChildren -> key不同,判定不同类型节点(div),执行createElm方法,进而创建新的dom节点;

为什么说使用index作为key容易出错

  • 复现步骤:在第一行的Input里输入1,在第二行Input里输入2,然后点第一行的“ד删除第一行
  • 期待结果:删除第一行后,应该变成“dog:2”
  • 实际结果:删除第一行后,变成了“dog:1”
<script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
<div id="app">
  <ul>
    <li v-for="(item, index) in list" :key="index">
      <test-row :name="item"></test-row>
      <span style="color: red;cursor: pointer" @click="handleRemove(index)">X</span>
    </li>
  </ul>
</div>
<script>
  Vue.component('test-row', {
    template: `<span>
      <span>{{ name }}:</span>
      <input v-model="nums"/>
      </span>`,
    props: {
      name: String
    },
    data() {
      return {
        nums: ''
      }
    }
  })
  new Vue({
    el: '#app',
    data() {
      return {
        list: ['cat', 'dog']
      }
    },
    methods: {
      handleRemove(i) {
        this.list.splice(i, 1);
      }
    }
  })
</script>

出现问题的原因:在patch阶段会认为这两个input子节点是sameVnode,进而复用原来的dom节点,因为组件只触发了更新,没有重新创建实例, 所以组件实例data数据没有变化,输入框内的内容就不会变化。

如果使用dog、cat作为key就可以避免这个bug;

以上就是vue中key使用的问题示例解析的详细内容,更多关于vue key使用问题的资料请关注脚本之家其它相关文章!

相关文章

  • vue3中使用vuex和vue-router的详细步骤

    vue3中使用vuex和vue-router的详细步骤

    这篇文章主要介绍了vue3中使用vuex和vue-router的步骤,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-12-12
  • 自定义Vue组件打包、发布到npm及使用教程

    自定义Vue组件打包、发布到npm及使用教程

    这篇文章主要介绍了自定义Vue组件打包、发布到npm及使用教程 ,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-05-05
  • vue.js利用defineProperty实现数据的双向绑定

    vue.js利用defineProperty实现数据的双向绑定

    本篇文章主要介绍了用Node.js当作后台、jQuery写前台AJAX代码实现用户登录和注册的功能的相关知识。具有很好的参考价值。下面跟着小编一起来看下吧
    2017-04-04
  • vue post application/x-www-form-urlencoded如何实现传参

    vue post application/x-www-form-urlencoded如何实现传参

    这篇文章主要介绍了vue post application/x-www-form-urlencoded如何实现传参问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-04-04
  • 基于vue 实现表单中password输入的显示与隐藏功能

    基于vue 实现表单中password输入的显示与隐藏功能

    这篇文章主要介绍了vue 实现表单中password输入的显示与隐藏功能 ,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-07-07
  • vue中子组件的methods中获取到props中的值方法

    vue中子组件的methods中获取到props中的值方法

    今天小编就为大家分享一篇vue中子组件的methods中获取到props中的值方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-08-08
  • element中el-cascader级联选择器只有最后一级可以多选

    element中el-cascader级联选择器只有最后一级可以多选

    本文主要介绍了element中el-cascader级联选择器只有最后一级可以多选,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-01-01
  • Vue封装Axios请求和拦截器的步骤

    Vue封装Axios请求和拦截器的步骤

    这篇文章主要介绍了Vue封装Axios请求和拦截器的步骤,帮助大家更好的对axios进行封装并将接口统一管理,同时为请求和响应设置拦截器interceptors。,感兴趣的朋友可以了解下
    2020-09-09
  • 前端使用print.js实现打印功能(基于vue)

    前端使用print.js实现打印功能(基于vue)

    最近新接了一个需求,想要在前端实现打印功能,下面这篇文章主要给大家介绍了关于前端使用print.js实现打印功能(基于vue)的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-05-05
  • Vue中的components组件与props的使用解读

    Vue中的components组件与props的使用解读

    这篇文章主要介绍了Vue中的components组件与props的使用解读,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-05-05

最新评论