Vue 数组元素修改与视图更新
Vue 中直接修改数组元素不会触发视图更新的原因及解决方案
问题
在 Vue 的 data 中有一个数组,直接通过索引修改数组元素时,视图是否会更新?
解答
不会触发视图更新
直接通过索引修改数组元素(如 this.array[0] = newValue)不会触发视图更新。
Vue 使用 Object.defineProperty 将 data 对象的属性转为 getter/setter 来追踪依赖变化。每个组件实例都有对应的 watcher,当依赖项的 setter 被调用时,会通知 watcher 重新计算并更新视图。但 Object.defineProperty 无法检测到数组索引的直接赋值操作。
触发视图更新的方法
1. 使用 Vue.set
通过索引设置数组元素:
Vue.set(this.array, 0, newValue)
// 或在组件中
this.$set(this.array, 0, newValue)
设置对象属性:
Vue.set(this.obj, 'newKey', newValue)
2. 使用 Vue.delete
删除数组元素:
Vue.delete(this.array, 0)
删除对象属性:
Vue.delete(this.obj, 'key')
3. 修改数组元素的属性
直接修改数组中对象的属性可以触发更新:
this.array[0].isShow = true
this.array.forEach(function(item) {
item.isShow = true
})
4. 替换整个数组
this.array = this.array.filter(item => item.id > 10)
5. 使用数组变异方法
Vue 包裹了以下数组方法,调用它们会触发视图更新:
this.array.push(newItem)
this.array.pop()
this.array.shift()
this.array.unshift(newItem)
this.array.splice(0, 1, newItem)
this.array.sort()
this.array.reverse()
关键点
- 直接通过索引修改数组元素不会触发视图更新,因为
Object.defineProperty无法检测数组索引变化 - 使用
Vue.set或this.$set可以响应式地修改数组元素或对象属性 - 修改数组中对象的属性可以触发更新,因为对象属性已被转为 getter/setter
- Vue 包裹了 7 个数组变异方法(push、pop、shift、unshift、splice、sort、reverse),调用它们会触发视图更新
- 替换整个数组也能触发更新
目录