bug复现

在代码中给一个对象,新增多个属性并赋值,然后在另一个方法中修改对象其中一个属性的值,发现数据改变,页面视图并没有更新

data: {
	return() {
		obj: {},
	}
},
methods: {
	fun1() {
		this.obj.a = 1;
		this.obj.b = 2;
	},
	fun2() {
		this.obj.a = 3;
	},
}
原因

翻了vue官方文档:

vue 无法检测 property 的添加或移除。由于 Vue 会在初始化实例时对 property 执行 getter/setter转化,所以 property 必须在 data 对象上存在才能让 Vue 将它转换为响应式的。对于已经创建的实例,Vue允许动态添加根级别的响应式 property。

看到这就大概清楚原因了,上面obj对象的属性a和b没有在data中定义,那a和b就不是响应式数据,后面修改这两个属性的值,自然也无法实时更新到视图。

怎么在console中判断是不是响应式数据

下面这张图可以看到有a和b都有get set属性,则这两个属性都为响应式数据,如果没有get set,则为非响应式
在这里插入图片描述

怎样才能设置为响应式数据

(1)像上面提到的,在data中定义了的就是响应式数据,如:

data: {
	return() {
		obj: {
			a: '',
			b: '',
		},
	}
},
// a和b为响应式数据

(2)如果一开始并不知道这个对象上会有哪些属性,怎么办?

  • 使用vue提供的vm.$set()方法,给对象增加属性值
// 这样obj的b属性就为响应式数据了
this.$set(this.obj,'b',2)
  • 如果要为对象赋值多个属性,则可以用Object.assign()
// 用原对象与要混合进去的对象的 property 一起创建一个新的对象。
this.obj = Object.assign({}, this.obj, { a: 1, b: 2 })
  • 还有一种方法,使用es6的对象扩展运算符
	this.obj.a = 1;
	this.obj.b = 2;
	this.obj = {...this.obj}; // 这里扩展运算符实质是深拷贝对象的属性

(3)如果是数组,即使在data中定义了,也无法检测到变动
参考vue官方文档:

Vue 不能检测以下数组的变动: 当你利用索引直接设置一个数组项时,
例如:vm.items[indexOfItem] = newValue
当你修改数组的长度时,例如:vm.items.length = newLength

以下三种方法设置数组为响应式数据:

  • $set()方法
this.$set(this.arr, 0, 'a'); // 设置数组第一个元素为arr = ['a']
  • splice()
this.arr.splice(0, 1, 'a');
  • 数组扩展运算符
this.arr[0] = 'a';
this.arr = [...this.arr];
Logo

前往低代码交流专区

更多推荐