vue的就地更新与v-for的key属性

vue的就地更新

Vue中的就地更新到底是怎么回事,为什么会存在就地更新的现象?

注意下面的例子,使用v-for指令时,没有绑定key值,才有就地更新的现象,因为Vue默认按照就地更新的策略来更新v-for渲染的元素列表

下面的例子很简单,就是循环遍历数据list,当li标签被点击的时候就进行删除操作。现在我们关心的并不是如何实现功能,而是点击删除按钮时,整个ElementsDOM结构树是如何变化的。
按照常理来说,如果我们点击第一个li标签的删除按钮,那么就应该删除第一个li标签,点击第二个删除按钮,就删除第二个li标签,依次类推。但实际上Vue并不是这样做的,那Vue是怎么做的呢?
比如说,我现在点击第二个li标签的删除按钮,第二个li标签的内容是item-2。实际上Vue是先将第三个li标签的内容item-3,移动到item-2<span></span>标签内部,然后再删除内容是item-3li标签。换句话说,就是点击第二个删除按钮,删除的并不是第二个li标签,其实删除的是第三个li标签,Vue只是将第三个li标签中<span></span>标签的内容item-3,移动到第二个li标签中的<span></span>标签内部。

const App = {
  data() {
    return {
      list: [
        {
          id: 1,
          value: 'item-1'
        },
        {
          id: 2,
          value: 'item-2'
        },
        {
          id: 3,
          value: 'item-3'
        }
      ]
    }
  },
  template:`
    <ul>
      <li 
        v-for="(item, index) of list"
      >
        <span>{{ item.value }}</span>
        <button  @click="handleClickDel(index)">Delete</button>
      </li>
    </ul>
  `,
  methods: {
    handleClickDel(index) {
      this.list.splice(index,1);
    }
  }
}

没有点击item-2时的dom结构

image.png

点击item-2的delete按钮时,dom树的变化

点击item-2Delete按钮时,我们发现DOM结构树发生了更改。注意Elements背景色是紫色的标签,背景是紫色说明标签内容发生了变化。那么我们之前说,Vue此时删除的并不是第二个li标签,只是将item-3字符串移动到第二个li标签中的<span></span>标签中,删除第三个li标签。所以我们从图中可以看到,第二个li标签内容发生变化,而第三个li标签被删除。这种现象就称为就地更新。
image.png

就地更新的优势

上面叙述了就地更新的现象,那为什么Vue中存在就地更新的现象呢?它的优势又是什么呢?我们再来看一个例子吧。
我们首先看模板template中的两个<div></div>标签有什么共同点呢?两个<div></div>标签中都拥有标签<a href="#"></a>,按照常理来说,如果变量isLogin返回的是Truthy(真值)的时候,那么第一个<div></div>标签内部的span、a标签都会被渲染;当isLogin返回的是Falsy(虚值)的时候,那么第二个<div></div>标签内部的两个a标签也都会被渲染。
但是实际上并不是这样滴,Vue拥有就地更新的现象。所以点击<a href="javascript:;" @click="isLogin = true">登录</a>的时候,Vue会将<a href="#">注册</a>标签内部的字符串注册文字改为xiaoming,对这个<a href="#"></a>标签进行复用🤔,而不是重新渲染一个新的DOM元素。
我们通过这个例子就能看出Vue中就地更新的优势,首先就地更新是非常高效的,能够复用其它的DOM元素,减少DOM操作,减少DOM元素的重绘与回流,减少浏览器的性能消耗。

const App = {
  data() {
    return {
      isLogin: false
    }
  },
  template:`
    <div
      v-if="isLogin"
    >
      <span>欢迎您~</span>
      <a href="#"> xiaoming </a>
    </div>  
    <div v-else>
      <a href="javascript:;" @click="isLogin = true">登录</a>
      <a href="#">注册</a>
    </div>
  `
}

就地更新的问题

默认模式是高效的,但是只适用于列表渲染输出的结果不依赖子组件或者临时的DOM状态(例如表单输入值)的情况。
我们如何理解“**只适用于列表渲染输出的结果不依赖子组件或者临时的DOM状态(例如表单输入值)的情况”**这句话呢?我们来通过下面的例子进行解释。

就地更新遇到临时的dom状态

下面的例子中,(图1)是DOM结构树初始化的状态。当我手动往input框输入值后,点击item-2Detele按钮,此时会出现(图2)的状态,我们发现Vue的的确确是按照就地更新的策略进行的渲染列表。但是我们输入框输入的值并没有进行更新。是因为我手动输入值的状态是临时DOM状态,Vue没有办法判断节点内部这个临时DOM状态有什么用,因此Vue并不去会跟踪这个状态。所以就地更新遇见临时DOM状态就会出现(图2)中的问题。

const App = {
  el:'#app',
  data () {
    return {
      list: [
        {
          id: 1,
          value: 'item-1'
        },
        {
          id: 2,
          value: 'item-2'
        },
        {
          id: 3,
          value: 'item-3'
        }
      ]
    }
  },
  template:`
    <ul>
      <li 
        v-for="(item, index) of list" 
        :key="item.id">
          <span> {{ item.value }} </span>
          <input type="text" />
          <button @click="deleteItem(index)">DELETE</button>
      </li>
    </ul>
  `,
  methods: {
    deleteItem(index) {
      this.list.splice(index,1);
    } 
  }
}

(图1)
image.png
(图2)
image.png
当然上面例子相当于这样的写法,此时tempArr变量是固定的,是不变化的;因为tempArr是不变化的,那么input标签内部绑定的value值是没有办法更新的,而碰上Vue当中的就地更新的策略就出现(图2)中同样的问题。

const App = {
  data() {
    return {
      tempArr: [1, 2, 3],
      list:[
        {
          id: 1,
          value: 'item-1'
        },
        {
          id: 2,
          value: 'item-2'
        },
        {
          id: 3,
          value: 'item-3'
        }
      ]
    }
  },
  template: `
  <div>
    <ul>
      <li v-for="(item,index) of list">
        <span> {{ item.value }} </span>
        <input type="text" :value="tempArr[index]" />
        <button @click="deleteItem(index)">DELETE</button>
      </li>
    </ul>
  </div>
  `,
  methods: {
    deleteItem(index) {
      this.list.splice(index, 1);
    }
  }
}

就地更新遇到子组件

Vue文档中指出就地更新**只适用于列表渲染输出的结果不依赖子组件,**也就是说你模板中列表渲染的结果不依赖子组件的时候就地更新策略不会出现问题。但是如果你模板中列表渲染的结果依赖子组件的时候,就地更新策略就会出现问题。因为子组件内部可能会有复杂的逻辑,所以Vue监控不了子组件内部的数据。
例如下面中的例子,列表渲染输出的结果依赖子组件MyComponent(需要子组件MyComponent),然后Vue中v-for指令默认按照就地更新策略进行渲染,所以出现(图3)中出现的问题。

const MyComponent = {
  props: {
    num: Number,
  },
  template: `
  <span> {{ num }} </span>
  `
}
const App = {
  components: {
    MyComponent
  },
  data() {
    return {
      list: [
        {
          id: 1,
          value: 'item-1'
        },
        {
          id: 2,
          value: 'item-2'
        },
        {
          id: 3,
          value: 'item-3'
        }
      ],
      tempArr:[1, 2, 3]
    }
  },
  template: `
  <div>
    <ul>
      <li v-for="(item, index) of list">
        <span> {{ item.value }} - </span>
        <my-component :num="tempArr[index]"></my-component>
        <input type="text" :value="tempArr[index]" />
        <button @click="deleteItem(index)">DELETE</button>
      </li>
    </ul>
  </div>
  `,
  methods: {
    deleteItem(index) {
      this.list.splice(index, 1);
    }
  }
};

(图3)
image.png

解决就地更新遇到的问题

解决Vue中就地更新的方法就是给循环的每一个标签绑定一个唯一的key值,并且key值不能够变更。添加key值之后就没有就地更新的现象出现了,因为添加唯一key值后,Vue后面的驱动能够追踪绑定的元素。
下面的例子中我们在v-for指令下绑定唯一的key值为item.id,此时按照常理来说已经可以解决就地更新遇见的问题,但是发现还是没有效果,v-for指令渲染列表时依旧使用的是就地更新的策略。这又是为什么呢?
原因在于<my-component :num="tempArr[index]" /><input type="text" :value="tempArr[index]" />标签中,tempArr[index]属性的index属性来源于v-for指令,因为这个index值会随着绑定的数据list长度的变化而变化,所以导致绑定的元素无法对应上,所以还是会执行就地更新的策略。
这也是为什么不推荐v-for指令中,绑定key值不要绑定index的原因,因为你的增加、删除操作会导致index值的变化,而如果绑定的key值在渲染之后还会不断的变化,那么导致在Vue底层中判断新老节点的结果一致(底层源码中通过a.key ===b.key判断key值),如果结果一致的话,就执行就地更新的策略。如果绑定的key值是静态的,那么新节点绑定的key值于老节点绑定的key值肯定不同,如果底层判断新老节点的结果不一致的话,会进行打补丁patch的其它逻辑判断,不会执行就地更新的逻辑,就能够追踪每一个绑定的节点。

const MyComponent = {
  props: {
    num: Number,
  },
  template: `
  <span> {{ num }} </span>
  `
}
const App = {
  components: {
    MyComponent
  },
  data() {
    return {
      list: [
        {
          id: 1,
          value: 'item-1'
        },
        {
          id: 2,
          value: 'item-2'
        },
        {
          id: 3,
          value: 'item-3'
        }
      ],
      tempArr:[1, 2, 3]
    }
  },
  template: `
  <div>
    <ul>
      <li 
        v-for="(item, index) of list"
        :key="item.id"
        >
        <span> {{ item.value }} - </span>
        <my-component :num="tempArr[index]"></my-component>
        <input type="text" :value="tempArr[index]" />
        <button @click="deleteItem(index)">DELETE</button>
      </li>
    </ul>
  </div>
  `,
  methods: {
    deleteItem(index) {
      this.list.splice(index, 1);
    }
  }
};

通过上述的逻辑,我们修改模板template的代码,将绑定过动态index值的地方都换成静态的属性item.id。按照分析,v-for指令渲染列表时候就不会执行就地更新的策略,Vue也就能够追踪绑定的元素。从(图4)也可以看出的的确确没有执行就地更新的策略。

 template: `
  <div>
    <ul>
      <li 
        v-for="(item, index) of list"
        :key="item.id"
        >
        <span> {{ item.value }} - </span>
        <my-component :num="item.id"></my-component>
        <input type="text" :value="item.id" />
        <button @click="deleteItem(index)">DELETE</button>
      </li>
    </ul>
  </div>
  `,

(图4)
image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/550268.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

windows Webrtc +VS2019 (M124)下载编译以及调通测试demo

下载depot tools 设置梯子 git config --global http.proxy 127.0.0.1:10000 git config --global https.proxy 127.0.0.1:10000 下载 $ git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git 设置depot_tools目录为环境变量 下载webrtc # 设置系统代…

CommunityToolkit.Mvvm笔记1---Instruction

CommunityToolkit.Mvvm是一个官方社区套件(Windows Community Toolkit)&#xff0c;延续了MVVMLight的风格&#xff0c;是一个现代、快速和模块化的 MVVM 库。 它是 .NET 社区工具包的一部分。 第一&#xff1a;入门安装 1&#xff0c;用NuGget安装&#xff0c;搜索Community…

.NET 发布,部署和运行应用程序

.NET应用发布 发布.Net应用有很多种方式&#xff0c;下面列举三种发布方式&#xff1a; 单文件发布跨平台发布Docker发布 单文件发布 右键工程&#xff0c;选择“发布”&#xff0c;部署模式选择“独立”&#xff0c;目标运行时选择自己想要部署到的系统&#xff0c;我这里用…

【Windows10】Anaconda3安装+pytorch+tensorflow+pycharm

文章目录 一、下载anaconda0.双击下载的文件1. 选择All users2. 安装路径3. 勾选环境变量和安装python4.安装完成5.添加环境变量6.测试是否安装成功 二、安装pytorch&#xff08;先看四&#xff01;先检查一下自己电脑是不是只能安装GPU版的1.查看conda图形化界面2.在安装pytor…

ES源码二:集群启动过程

命令行参数解析 Elasticsearch&#xff1a;在main里面创建了Elasticsearch实例&#xff0c;然后调用了main方法&#xff0c;这个main方法最终会调用到父类Command的main方法 这里做了几件事&#xff1a; 注册一个 ShutdownHook&#xff0c;其作用就是在系统关闭的时候捕获IO…

使用SpringBoot3+Vue3开发公寓管理系统

项目介绍 公寓管理系统可以帮助公寓管理员更方便的进行管理房屋。功能包括系统管理、房间管理、租户管理、收租管理、房间家具管理、家具管理、维修管理、维修师傅管理、退房管理。 功能介绍 系统管理 用户管理 对系统管理员进行管理&#xff0c;新增管理员&#xff0c;修改…

CentOS 7开机启动过程,引导和服务,密码的修改

开机启动过程&#xff1a; 引导过程&#xff1a;1.开机自检(BIOS)->2.MBR引导->GRUB菜单->加载内核kernel->systemd进程初始化 程序&#xff1a;执行特定任务的一串代码&#xff0c;静态&#xff0c;存在硬盘中。 进程&#xff1a;运行中的程序叫进程&#xff0…

Unity 点击次数统计功能

介绍 &#x1f4a1;.调用方便&#xff0c;发生点击事件后直接通过"xxx".CacheClick缓存 &#x1f4a1;. 在允许的时间间隔内再次点击会累计点击次数&#xff0c;直到超出后触发事件 传送门&#x1f448;

计算机视觉——OpenCV Python基于颜色识别的目标检测

1. 计算机视觉中的颜色空间 颜色空间在计算机视觉领域的应用非常广泛&#xff0c;它们在图像和视频处理、物体检测等任务中扮演着重要角色。颜色空间的主要作用是将颜色以数值形式表示出来&#xff0c;这样计算机算法就能够对其进行处理和分析。不同的颜色空间有着不同的特点和…

uniapp--登录和注册页面-- login

目录 1.效果展示 2.源代码展示 测试登录 login.js 测试请求 request.js 测试首页index.js 1.效果展示 2.源代码展示 <template><view><f-navbar title"登录" navbarType"4"></f-navbar><view class"tips"><…

2024蓝桥杯每日一题(最大公约数)

备战2024年蓝桥杯 -- 每日一题 Python大学A组 试题一&#xff1a;公约数 试题二&#xff1a;最大公约数 试题三&#xff1a;等差数列 试题四&#xff1a;最大比例 试题五&#xff1a;Hankson的趣味题 试题一&#xff1a;公约数 【题目描述】 …

冯喜运:4.16晚间关注原油EIA数据黄金原油分析

【 黄金技术面分析】&#xff1a;周二黄金价格日内走跌&#xff0c;白盘低点触及2363一线止跌反弹&#xff0c;实时现报价2372一线。目前小时线布林带逐步收口&#xff0c;上轨位于2392一线&#xff0c;下轨布林带在2351位置。今晚阻力关注2389和今日高点2392区域&#xff0c;其…

二级综合医院云HIS系统源码,B/S架构,采用JAVA编程,集成相关医保接口

二级医院云HIS系统源码 云HIS系统是一款满足基层医院各类业务需要的健康云产品。该产品能帮助基层医院完成日常各类业务&#xff0c;提供病患预约挂号支持、病患问诊、电子病历、开药发药、会员管理、统计查询、医生工作站和护士工作站等一系列常规功能&#xff0c;还能与公卫…

海外云手机为什么适合社媒运营?

如今&#xff0c;社媒营销如果做得好&#xff0c;引流效果好的账号&#xff0c;可以用来带货变现&#xff0c;而外贸、品牌出海也同样都在做社媒营销&#xff0c;Tik Tok、facebook、ins等热门的海外社媒平台都是行业密切关注的&#xff0c;必要的时候&#xff0c;大家会使用海…

基于微信小程序投票评选系统的设计与实现(论文+源码)_kaic

摘 要 社会发展日新月异&#xff0c;用计算机应用实现数据管理功能已经算是很完善的了&#xff0c;但是随着移动互联网的到来&#xff0c;处理信息不再受制于地理位置的限制&#xff0c;处理信息及时高效&#xff0c;备受人们的喜爱。所以各大互联网厂商都瞄准移动互联网这个潮…

Unity类银河恶魔城学习记录12-18,19 p140 Options UI-p141 Finalising ToolTip源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili UI_ToolTip.cs using TMPro; using UnityEngine;public class UI_ToolTip :…

AppleScript初体验,让你的mac实现自动化UI操作

AppleScript 简介 AppleScript是苹果公司开发的一种脚本语言&#xff0c;用于操作MacOS及其应用程序&#xff0c;在实现MacOS自动化工作方面非常给力。 我们可以使用AppleScript用来完成一些重复琐碎的工作&#xff0c;AppleScript具有简单自然的语法&#xff0c;另外系统也提…

智能零售:引领购物新时代

智能零售通过整合人工智能、物联网、大数据和机器学习等技术&#xff0c;正在彻底改变传统的购物模式&#xff0c;为消费者和零售商提供前所未有的效率和个性化体验。 智能零售利用消费者数据分析来提供个性化的购物推荐。无论是在线平台或是实体店内&#xff0c;智能系统都能…

C#语法知识之变量

2.变量 一、知识点 1、折叠代码 //#region按Tab键#region MyRegion(描述)#endregion //本质是编译器提供给我们的预处理指令&#xff0c;发布代码是会被自动删除2、声明变量和变量类型 ​ 变量就是可以变化的容器&#xff0c;用来存储各种不同类型数值的一个容器&#xff1b…

和鲸科技将参与第五届空间数据智能学术会议并于应急减灾与可持续发展专题论坛做报告分享

ACM SIGSPATIAL中国分会致力于推动空间数据的研究范式及空间智能理论与技术在时空大数据、智慧城市、交通科学、社会治理等领域的创新与应用。ACM SIGSPATIAL中国分会创办了空间数据智能学术会议&#xff08;SpatialDI&#xff09;&#xff0c;分会将于2024年4月25日-27日在南京…