Vue中关于数组与对象修改触发页面更新的机制与原理简析

相关问题

数组

使用索引直接赋值与直接修改数组length时,不会触发页面更新。

例如:

<script>
export default {
name: "HomeView",
data: () => ({
list1: ["A", "B"],
}),
methods: {
btnClicked() {
this.list1[0] = "C"
this.list1[2] = "C"
},
},
}
</script>

或是

<script>
export default {
name: "HomeView",
data: () => ({
list1: [{ text: "123" }, { text: "456" }],
}),
methods: {
btnClicked() {
this.list1[0] = { text: "789" }
},
},
}
</script>

页面并不会触发更新。

对象

页面初始化完成后,在方法中直接对data内声明对象当前不存在的属性进行赋值来为对象新增属性时,页面也不会响应渲染。

例如:

<script>
export default {
name: "HomeView",
data: () => ({
obj1: { a: "a", b: "b" },
}),
methods: {
btnClicked() {
this.obj1.c = "c"
},
},
}
</script>

页面并不会触发更新。

原因

Vue在初始化时会将data内所有的属性嵌套遍历并重写其Getter和Setter方法,借此实现响应式属性。

然而对于在页面渲染完成后加入data的属性,Vue并不会将其变为响应式。

一些深入的探究

数组

Vue对于数组是仅将其对应下标的对象的属性变为响应式,而这个下标本身是无法成为响应式的

data: () => ({
list1: [{ text: "123" }, { text: "456" }],
})

使用如上的data声明。

方法A:

this.list1[0] = { text: "789" }

方法B:

this.list1[0].text = "789"

方法B可以被正确响应而方法A不可以。

方法A将数组下标为0的位置替换为了一个新的对象,而因为数组下标不是响应式的,因此没有触发页面刷新。

同时,由于数组下标为0的位置替换为了一个新的对象,而这个新的对象并没有被配置为响应式,那对于这个对象属性的修改也不会触发页面更新。如下:

this.list1[0] = { text: "789" }
this.list1[0].text = "456"

由于新的对象的属性并没有被配置为响应式,那么即使对这个对象的属性进行修改,页面也不会被更新。

既然下标本身无法成为响应式,不妨尝试:

<script>
export default {
name: "HomeView",
data: () => ({
list1: ["A", "B"],
}),
methods: {
btnClicked() {
this.list1[0] = "C"
},
},
}
</script>

通过下标修改数组的对应值也无法触发视图更新。

对象

data: () => ({
obj1: { a: { text: "a" }, b: { text: "b" } },
}),

使用如上的data声明。

this.obj1.a = { text: "c" }

成功触发视图更新。

与数组下标不同,对象的属性在初始化是被定义为响应式的,因此直接对属性赋值对象是能够触发视图更新的。不像对数组的对应下标赋值而不会触发视图更新。

解决方案

数组

1. 内置API

如果需要向数组加入新的成员,则可以直接使用数组的push方法。

此外,下列数组方法也可以自动的触发视图刷新:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

2. 将数组重新赋值,修改引用地址

为数组新增一个字符串成员"C"
this.list1 = this.list1.concat(["C"])

由于list1是data的属性,list1的引用发生改变,就会触发视图更新

修改数组的第一个值
let tempList = this.list1.concat([]) // 深拷贝,等价于一个新数组,使用slice,JSON都可以。
tempList[0] = "666"
this.list1 = tempList

通过原数组新建一个新数组,修改新数组后再将新数组赋值给原数组,由于原数组作为data的属性,其引用被修改触发视图更新

3. Vue.$set() 方法

使用Vue.$set可以为data对象添加一个新的响应式属性,且触发视图更新

定义:

Vue.$set(对象或数组, 对象属性名或数组下标, 值)

向list1对象的0索引位置赋值一个新的响应式对象,同时触发视图更新:

Vue.$set(this.list1, 0, { text: "789" })

如果在组件中应使用this.$set来代替:

this.$set(this.list1, 0, { text: "789" })

对象

1. 将对象重新赋值,修改引用地址

思路与数组的类同。

使用JSON、手写递归、lodash深拷贝均可,但如果对象内含方法,则不能使用JSON来完成深拷贝。

深拷贝完成后修改对应属性后赋值给原对象即可。

2. Vue.$set() 方法

对象同样可以使用$set() 方法修改。

定义:

Vue.$set(对象或数组, 对象属性名或数组下标, 值)

将obj1对象的a属性赋值为字符串"b"并触发视图更新:

Vue.$set(this.obj1, a, "b")

如果在组件内,则应使用:

this.$set(this.obj1, a, "b")

Vue中关于数组与对象修改触发页面更新的机制与原理简析的更多相关文章

  1. vue数组对象修改触发视图更新

    直接修改数组元素是无法触发视图更新的,如 this.array[0] = { name: 'meng', age: 22 } 修改array的length也无法触发视图更新,如 this.array. ...

  2. vue中改变数组或对象,页面没做出对应的渲染

    原文链接 数组更新检测 变异方法 Vue 包含一组观察数组的变异方法,所以它们也将会触发视图更新.这些方法如下: push() pop() shift() unshift() splice() sor ...

  3. vue中watch数组或者对象

    1.普通的watch data() { return { frontPoints: 0 } }, watch: { frontPoints(newValue, oldValue) { console. ...

  4. 【VUE】vue中遍历数组和对象

    一.遍历对象 对象数据 cities:{ "A":[{ "id": 56, "spell": "aba", " ...

  5. 用VUE监听数组和对象的变化

    看一下演示代码,先是增加数组和对象. <template> <div> <p>这是我定义的数组</p> <div>{{this.arr}}& ...

  6. Vue不能检测数组或对象变动问题的解决

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. Vue实现对数组、对象的深拷贝、复制

    当组件间传递对象时,由于此对象的引用类型指向的都是一个地址(除了基本类型跟null,对象之间的赋值,只是将地址指向同一个,而不是真正意义上的拷贝),如下 数组: ,,]; var b = a; b.p ...

  8. vue中改变数组的值视图无变化

    今天开发的时候遇到一个多选取消点击状态的,渲染的时候先默认都选中,然后可以取消选中,自建了一个全为true的数组,点击时对应下标的arr[index]改为false,数据改变了状态没更新,突然想起来单 ...

  9. JS中深拷贝数组、对象、对象数组方法

    我们在JS程序中需要进行频繁的变量赋值运算,对于字符串.布尔值等可直接使用赋值运算符 “=” 即可,但是对于数组.对象.对象数组的拷贝,我们需要理解更多的内容. 首先,我们需要了解JS的浅拷贝与深拷贝 ...

  10. JS中深拷贝数组、对象、对象数组方法(转载)

    我们在JS程序中需要进行频繁的变量赋值运算,对于字符串.布尔值等可直接使用赋值运算符 “=” 即可,但是对于数组.对象.对象数组的拷贝,我们需要理解更多的内容. 首先,我们需要了解JS的浅拷贝与深拷贝 ...

随机推荐

  1. CentOS 7配置Chrony服务进行时间同步

    CentOS 7版本中使用Chrony工具实现本地时间与标准时间同步.与CentOS 6版本中的NTP服务不同,Chrony可以更快更准确地同步系统时钟,最大程度的减少时间和频率误差.Chrony包含 ...

  2. CentOS obs直播RTMP协议推流到Nginx流媒体服务器到VUE使用HLS直播

    1. 发布打包前端管理平台(ant-design-vue) 2. 发布打包后端(.NET6-WebApi) .NET6 webAPI orm: free sql 数据库:mysql5.7 3. 发布打 ...

  3. Optional 常用方法总结

    转载请注明出处: Optional 类是 JAVA 8 提供的判断程序是否为空提供的包装工具类:可以减少代码中的 是否为空的判断,以及减少 NullPointerExceptions:使得程序变得更为 ...

  4. C#-8 数组

    一 关于数组 数组是由一个变量名称表示的一组同类型的数据元素.数组中的元素通过变量名和方括号索引来访问. int[] intArray = new int[] { 1, 2, 3 }; //声明了一个 ...

  5. 220722 T4 求和 /P4587 [FJOI2016]神秘数 (主席树)

    好久没打主席树了,都忘了怎么用了...... 假设我们选了一些数能构成[0,x]范围内的所有值,下一个要加的数是k(k<=x+1),那么可以取到[0,x+k]内的所有取值,所以有一种做法: 对于 ...

  6. NOIP2017总结 & 题解

    day1t1的结论貌似在哪见过,自己稍微验证了一下貌似没记错就没有管了.t2一道很好(keng)的模拟题啊t3自己做题好慢啊,想出来dp打上去最后几分钟才过了大样例,我写的是记忆化搜索,判-1很好判, ...

  7. VS Code For Web 深入浅出 -- 进程间通信篇

    在上一篇中,我们一起分析了 VS Code 整体的代码架构,了解了 VS Code 是由前后端分离的方式开发的.且无论前端是基于 electron 还是 web,后端是本地还是云端,其调用方式并无不同 ...

  8. Linux基础_4_文件夹管理

    文件路径 . #表示当前目录,同./ .. #表示上级目录,同../ ../../ #表示上上级目录 / #表示根目录 注:文件名长度不超过255个字符 注:.开头为隐藏文件 切换目录 cd #默认切 ...

  9. 在vue页面引入echarts,图表的数据来自数据库 springboot+mybatis+vue+elementui+echarts实现图表的制作

    文章目录 1.实现的效果 2.前端代码 3.后端controller代码 4.servie层代码 5.serviceImpl层代码 6.mapper层代码 7.xml中的sql语句 8.遇到的问题 8 ...

  10. JUC(7)四大函数式接口

    文章目录 1.四大函数式接口(必须掌握) 1.1 function 1.2 Predicate 1.3 Consumer 1.4 Supplier 1.四大函数式接口(必须掌握) 1.lambda表达 ...