在Vue中使用v-for渲染列表时,默认使用就地更新策略。该策略默认是基于索引的,规定在列表绑定的数据元素顺序变化时,不会重新创建整个列表,而只是更新对应DOM元素上的数据。以下代码实现了一个TODO列表的勾选、添加和删除功能:

<!DOCTYPE html>
<html> <head>
<title>In-Place Update Example</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head> <body>
<div id="app">
<ul>
<li v-for="(todo, index) in todos" :key="index">
<input type="checkbox" v-model="todo.completed">
{{ todo.text }}
<button @click="removeTodo(index)">Remove</button>
</li>
</ul>
<button @click="addTodo">Add Todo</button>
</div> <script>
const app = new Vue({
el: '#app',
data: {
todos: [
{ text: 'Learn Vue.js', completed: false },
{ text: 'Build an app', completed: true },
{ text: 'Deploy to production', completed: false }
]
},
methods: {
removeTodo(index) {
this.todos.splice(index, 1);
},
addTodo() {
this.todos.push({ text: 'New Todo', completed: false });
}
}
});
</script>
</body> </html>

该策略模式是高效的,避免了大量的DOM重排重绘。

然而,该策略基于一个前提:列表项内部的内容不依赖于子组件的状态或临时的DOM状态。如违背该前提,就可能导致意外,因为Vue不会重新创建子组件或恢复临时DOM状态。

下面代码实现了v-for列表项内容依赖于子组件的状态而导致意外的情况:

<!DOCTYPE html>
<html> <head>
<title>In-Place Update with Child Component</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head> <body>
<div id="app">
<!-- 使用 v-for 渲染子组件列表 -->
<child-component v-for="(item, index) in itemList" :key="index"
@remove="removeItem(index)"></child-component>
</div> <script>
Vue.component('child-component', {
template: `
<div>
<!-- 子组件的内容和状态 -->
<button @click="increment">{{ count }}</button>
<!-- 删除 -->
<button @click="$emit('remove')">删除</button>
</div>
`,
methods: {
increment() {
this.count++;
}
},
data(){
return{
count:0
}
}
}); const app = new Vue({
el: '#app',
data: {
itemList: new Array(5).fill(null)
},
methods: {
removeItem(index) {
this.itemList.splice(index, 1);
}
}
});
</script>
</body> </html>

我们先点击某项计数器,再删除该项:

为了解决该问题,我们为每一项绑定一个唯一的key属性:

<!DOCTYPE html>
<html> <head>
<title>In-Place Update with Child Component</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head> <body>
<div id="app">
<!-- 使用 v-for 渲染子组件列表 -->
<child-component v-for="(item, index) in itemList" :key="item.id"
@remove="removeItem(index)"></child-component>
</div> <script>
Vue.component('child-component', {
template: `
<div>
<!-- 子组件的内容和状态 -->
<button @click="increment">{{ count }}</button>
<!-- 删除 -->
<button @click="$emit('remove')">删除</button>
</div>
`,
methods: {
increment() {
this.count++;
}
},
data(){
return{
count:0
}
}
}); const app = new Vue({
el: '#app',
data: {
// 为每一项添加一个id
itemList: [
{ id: 0 },
{ id: 1 },
{ id: 2 }
]
},
methods: {
removeItem(index) {
this.itemList.splice(index, 1);
}
}
});
</script>
</body> </html>

效果如下:

那么就有疑问了:为什么前面代码中的key属性绑定了index没有用呢,index难道不是唯一的吗?很简单,这是由于我们删除的是数据项,而不是数组索引,使用id就不会有这个问题,删除一项连带着删除了该唯一id。

关于Vue的就地更新策略的解析的更多相关文章

  1. Unity手游之路<十三>手游代码更新策略探讨

    http://blog.csdn.net/janeky/article/details/25923151 这几个月公司项目非常忙,加上家里事情也多,所以blog更新一直搁置了.最近在项目开发上线过程中 ...

  2. Unity手游之路手游代码更新策略探讨

    版权声明: https://blog.csdn.net/janeky/article/details/25923151 这几个月公司项目非常忙.加上家里事情也多,所以blog更新一直搁置了. 近期在项 ...

  3. vue的就地复用--- v-for与:key

    v-for遵循的是vue的就地复用原则.文本与数据是绑定的,所以当文本被重新渲染的时候,列表也会被重新渲染. 就地复用只适用于不依赖子组件状态或临时DOM状态的列表渲染输出.[比如表单输入值的列表渲染 ...

  4. Unity手游之路<十二>手游资源热更新策略探讨

    http://blog.csdn.net/janeky/article/details/17666409 上一次我们学习了如何将资源进行打包.这次就可以用上场了,我们来探讨一下手游资源的增量更新策略. ...

  5. 分布式系统中一些主要的副本更新策略——Dynamo/Cassandra/Riak同时采取了主从式更新的同步+异步类型,以及任意节点更新的策略。

    分布式系统中一些主要的副本更新策略. 1.同时更新 类型A:没有任何协议,可能出现多个节点执行顺序交叉导致数据不一致情况. 类型B:通过一致性协议唯一确定不同更新操作的执行顺序,从而保证数据一致性 2 ...

  6. [unity3d]手游资源热更新策略探讨

    原地址:http://blog.csdn.net/dingxiaowei2013/article/details/20079683 我们学习了如何将资源进行打包.这次就可以用上场了,我们来探讨一下手游 ...

  7. 利用Dnspod api批量更新添加DNS解析【python脚本】 - 推酷

    利用Dnspod api批量更新添加DNS解析[python脚本] - 推酷 undefined

  8. odi增量更新策略

    增量更新策略:通过一个“update key”比较流数据记录与目标表中的记录比较进行数据整合.具有相同“update key”的记录当相关联列不同时将被更新:在目标表中不存在的记录将被插入.这种方式用 ...

  9. vue加载优化策略

    vue.js是一个比较流行的前端框架,与react.js.angular.js相比来说,vue.js入手曲线更加流畅,不管掌握多少都可以快速上手.但是单页面应用也都有其弊病,有时候首屏加载慢的让人捏舌 ...

  10. [转]Unity手游之路<十二>手游资源热更新策略探讨

    最近梳理了下游戏流程.恩,本来想写下,但是,还是看前辈的吧 版权声明: https://blog.csdn.net/janeky/article/details/17666409 上一次我们学习了如何 ...

随机推荐

  1. 2022-09-16:以下go语言代码输出什么?A:101;B:100;C:1;D:2。 package main import ( “fmt“ ) type MS struct {

    2022-09-16:以下go语言代码输出什么?A:101:B:100:C:1:D:2. package main import ( "fmt" ) type MS struct ...

  2. 2021-04-27:如果一个字符相邻的位置没有相同字符,那么这个位置的字符出现不能被消掉。比如:“ab“,其中a和b都不能被消掉 。如果一个字符相邻的位置有相同字符,就可以一起消掉。比如:“abbb

    2021-04-27:如果一个字符相邻的位置没有相同字符,那么这个位置的字符出现不能被消掉.比如:"ab",其中a和b都不能被消掉 .如果一个字符相邻的位置有相同字符,就可以一起消 ...

  3. Golang指针隐式间接引用

    1.Golang指针 在介绍Golang指针隐式间接引用前,先简单说下Go 语言的指针 (Pointer),一个指针可以指向任何一个值的内存地址 它指向那个值的内存地址,在 32 位机器上占用 4 个 ...

  4. HashMap 底层是如何实现的?

    HashMap 在不同的 JDK 版本下的实现是不同的,在 JDK 1.7 时,HashMap 底层是通过数组 + 链表实现的:而在 JDK 1.8 时,HashMap 底层是通过数组 + 链表或红黑 ...

  5. 【技术积累】Java中的JVM【一】

    什么是JVM JVM英文全称为Java Virtual Machine,中文意为Java虚拟机.JVM是一种能够执行Java语言编写的程序的虚拟机器,它首次作为Java语言的一部分,后来又被移植到了许 ...

  6. 【python基础】文件-初识文件

    文本文件可存储的数据量是非常多的.每当需要分析或修改存储在文件中的信息时,首先就是读取文件到内存中,为此可以一次性读取文件的全部内容,也可以以每次一行的方式逐步读取. 1.读取文件 1.1读取整个文件 ...

  7. uniapp微信小程序转支付宝小程序踩坑(持续更新)

    首先第一个,真有被折磨到! // 微信正常使用,支付宝不行 <image src="https://static.dabapiao.com/images/coupon-index.pn ...

  8. String解析及其方法

    String解析及其方法 1.前言 2.什么是字符串(String) 3.字符串(String)的两种创建方式及其区别 4.字符串(String)的方法及其部分原码解析 5.字符串(String)的弊 ...

  9. [Java基础]String,StringBuffer,StringBuilder的区别

    String 和 StringBuffer/StringBuilder应该分开来看 java.lang.String源码中的注释说明 java.lang.StringBuffer源码中的注释说明 ja ...

  10. 【Springboot】拦截器

    Springboot 拦截器 1.什么是拦截器? 拦截器可以根据 URL 对请求进行拦截,主要应用于登陆校验.权限验证.乱码解决.性能监控和异常处理等功能. 2.定义拦截器步骤 在 Spring Bo ...