为什么新增属性、数组下标赋值有时不更新
先理解原理和示例,再练习完整口述与追问。
回答要点
Vue2 对未声明属性新增 / 删除、直接写数组索引或 length 有检测限制。优先预声明字段;已有响应式嵌套对象可用 this.$set,数组可用 splice 或替换为新数组。根级字段不能靠事后随意添加解决。
原理拆解
Vue2 初始化时只能对当时存在的对象键逐个定义访问器,因此直接新增键不会自动拥有对应 setter。数组下标和 length 直接变化不走 Vue2 封装的数组通知路径,但 push、splice 等被重写的方法会通知。Vue.set 对已有键可赋值,对数组索引用 splice,对合适的已观察对象新增键则定义响应式属性并通知对象层依赖。
示例与推演
// Vue2 组件 methods 中,user 和 rows 已在 data 声明
this.$set(this.user, 'nickname', 'Lin')
this.rows.splice(0, 1, { id: 1, name: 'new' })
this.user = { ...this.user, city: 'Shanghai' }
最后一种是给已声明的 user 根字段设置新对象,新对象会被观察;它不同于直接给实例增加一个未声明根字段。
易错点
不要在 Vue3 中继续套用“所有新增键都必须 $set”的结论。初始化就能确定的表单字段应先声明;更新正常却未显示时,还要检查模板实际读取的是不是同一对象。
参考回答可直接练习口述
Vue2 初始化时无法为未来所有属性预先建立 getter/setter,数组索引和 length 的直接写入也可能绕过检测。我先预声明页面状态;对响应式嵌套对象用 this.$set 添加字段,数组用 splice 或替换为新数组。用 Object.assign 原地补字段不保证新字段响应;把新对象赋给已经响应式的 form 字段,则会重新观察它。不要用 forceUpdate 把这类状态设计问题掩盖掉。