前言
在 Vue 2 开发中,你是否遇到过“明明数据变了,视图却没动”的诡异情况?这通常不是代码逻辑问题,而是由于 Vue 2 基于 Object.defineProperty 的响应式原理存在天然的局限性。本文将带你攻克这些响应式盲区。
一、 响应式的“硬伤”:为什么会失效?
Vue 2 在初始化阶段,会遍历 data 中的属性并使用 Object.defineProperty 将其转为 getter/setter。
它的核心问题在于:
- 无法检测对象属性的添加或删除(因为它只在初始化时进行监听)。
- 无法检测数组索引的直接修改和长度变化。
二、 对象操作:打破“属性新增”的僵局
1. 新增/删除属性
如果你直接通过 this.obj.newKey = value 赋值,Vue 是无法感知的。
-
新增属性:使用
this.$set(或全局Vue.set)。- 语法:
this.$set(target, key, value) - 示例:
this.$set(this.user, 'age', 18)
- 语法:
-
删除属性:使用
this.$delete(或全局Vue.delete)。
2. 批量修改属性
如果你需要一次性增加多个属性,不要写一堆 $set,Vue2 可以监听对象引用变化,最高效的方法是替换整个对象引用:
// 这种方式 Vue 能够通过监听对象的引用变化来触发更新
this.user = Object.assign({}, this.user, {
age: 18,
gender: 'male'
});
// 批量更新user对象属性
this.user = {
...this.user,
age: 20,
gender: '男',
address: '北京'
}
三、 数组操作:被“重写”的 7 个方法
在 Vue 2 中,直接执行 this.items[0] = 'new' 是不会触发更新的。解决方案同样是使用 this.$set,以及使用vue重写的相关数组方法。
1. 自动触发更新的方法
只要调用以下方法,Vue 就会自动检测到变化并更新视图:
push()/pop():队尾操作unshift()/shift():队头操作splice():最万能,可实现增、删、改。sort():排序。reverse():翻转。
2. 数组的特殊场景
-
根据索引修改值:
- ❌ 错误:
this.items[index] = newValue - ✅ 正确:
this.$set(this.items, index, newValue)或this.items.splice(index, 1, newValue)
- ❌ 错误:
-
修改数组长度:
- ❌ 错误:
this.items.length = 0(清空数组失效) - ✅ 正确:
this.items.splice(0)或this.items = []
- ❌ 错误:
四、 进阶补充:Vue 3 是如何解决的?
-
Vue 3 使用了 ES6 Proxy:Proxy 代理的是整个对象而不是属性。
-
优势:Proxy 可以原生监听到属性的动态添加、删除,以及数组索引的变化,因此在 Vue 3 中,你不再需要使用
$set了!
五、 总结
-
vue2对象新增属性:首选
this.$set,批量新增选Object.assign。 -
vue2数组修改:养成使用
splice或push等 7 个变异方法的习惯。 -
调试技巧:如果视图没更新,先用
console.log确认数据是否变了,再检查是否触碰了上述响应式盲区。