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. 使用k8s部署springcloud解决三大问题

    1.正式环境使用的话启动时需要指定使用正式的配置文件,这个要咋处理? 解决办法 文章地址:https://www.cnblogs.com/sanduzxcvbnm/p/13262411.html 分析 ...

  2. 在 Fedora 中使用 Cockpit 创建虚拟机

    本文向你展示如何在 Fedora 31 上使用安装 Cockpit 所需软件来创建和管理虚拟机.Cockpit 是一个交互式管理界面,可让你在任何受支持的 Web 浏览器上访问和管理系统.随着 vir ...

  3. Mysql三种日志(binlog,redolog,undolog)的作用和区别

    Mysql有三种很重要的日志也是面试经常涉及到的考点,分别是 binlog .redo log和undo log, 这里面binlog 是server层实现的日志,而redo log 和undo lo ...

  4. Git使用与心得体会

    Git使用与心得体会 一.闲聊 闲暇时间学一下Git,也算是不用在网页端操作github了 二.Git相关 集中式与分布式 Git是一个分布式的版本控制系统,而传统的SVN则属于集中式 集中式与分布式 ...

  5. 安装 LAMP 环境(yum 版本) shell脚本

    #!/bin/bash # 安装 LAMP 环境(yum 版本) # 本脚本适用于 RHEL7(RHEL6 中数据库为 mysql) yum makecache &>/dev/null ...

  6. win10+ubuntu双系统的坑

    1.把U盘里\EFI\BOOT\grubx64.efi文件重命名为mmx64.efi,避免系统提示缺少文件而退出安装: 2.如果电脑显卡为N卡,则在install Ubuntu时,按e进入编辑,在qu ...

  7. 13.内建函数eval()

      eval函数 eval()函数十分强大 -- 将字符串当成有效的表达式来求值并返回计算结果 例如下图,eval会将字符串的引号去掉并且计算返回结果  

  8. vue3+element-plus+登录逻辑token+环境搭建

    vue3+element-plus+登录逻辑token环境搭建 安装脚手架工具 1 npm i @vue/cli@4.5.13 -g 验证是否安装成功 1 vue -V # 输出 @vue/cli 4 ...

  9. 题解UVA10948 The primary problem

    前言 前置 \(\sf{Solution}\) 既然有了 \(n\) ,那找出 \(a\) 和 \(b\) 就只要枚举 \(a\) 的范围 \(1\sim n\),判断 \(a\) 和 \(n-a\) ...

  10. 题解 UVA439 骑士的移动 Knight Moves

    前言 最近板子题刷多了-- 题意 一个 \(8\times 8\) 的棋盘,问马从起点到终点的最短步数为多少. \(\sf Solution\) 要求最短路径嘛,显然 bfs 更优. 读入 这个读入处 ...