Vue 添加响应式属性的正确姿势

Vue 添加响应式属性的正确姿势

💡 原文中文,约3100字,阅读约需8分钟。
📝

内容提要

Vue 2 中直接给实例赋值新属性不会触发响应式,因为初始化时仅劫持了 data 中已有属性。正确方法:使用 Vue.set 或 $set 手动劫持;无需双向绑定时可用 $forceUpdate 强制渲染;也可用 :value 加 @input 模拟单向绑定。数组可用 push 等包裹方法或整体赋值。注意:若属性已被直接赋值,再用 set 也无法使其响应式。

🔎

延伸解读

直接赋值为何破坏响应式

Vue 2 在初始化时递归遍历 data,为已有属性设置 getter 和 setter,从而建立响应式。若直接给对象添加新属性,如 this.inputvalue.aaaa = 'aaaa',该属性未经此过程,因此即使被视图读取,也无法通知更新。这解释了动态新增属性不触发视图渲染的根本原因。

set 与 forceUpdate 的适用场景

Vue.set 或 $set 可手动将新属性转为响应式,适用于需要双向绑定或依赖自动更新的场景。若仅需单向数据流,可用 $forceUpdate 强制重新渲染,但数据变化不会自动同步到视图。两者选择取决于是否需要持续的响应式追踪。

数组更新的特殊处理

数组本身可通过 push、pop、splice 等包裹方法触发更新,或整体重新赋值。若数组元素是对象,则对象内部新增属性仍需遵循上述规则。直接修改数组索引或长度不会触发响应式,需使用 Vue.set 或数组方法。

先直接赋值后 set 失效的陷阱

若属性已被直接赋值,即使后续调用 set 也无法将其转为响应式,因为 set 对已存在的属性不会再次劫持。这导致 v-model 与 @input 混用时出现更新异常:先通过 @input 静态添加属性,再使用 v-model 便无法触发更新。因此应避免先直接赋值再补救。

❓

Q&A

Vue 2 中为什么直接给对象添加新属性不会触发视图更新?

因为 Vue 在初始化时只会对 data 中已有的属性递归设置 getter 和 setter(劫持),新添加的属性没有经过这个劫持过程,所以即使有订阅者,属性本身也意识不到,无法触发更新。

在 Vue 2 中如何正确动态添加响应式属性?

使用 Vue.set 或实例的 $set 方法向响应式对象添加属性,手动触发一次劫持,这样新属性就是响应式的,能触发视图更新。

Vue 2 中 $forceUpdate 有什么作用?什么时候用?

$forceUpdate 可以强制重新渲染视图。当动态添加了属性但不需要双向绑定,且数据已修改但视图未更新时,可以使用它来强制更新。

Vue 中如何模拟单向绑定?

可以使用 :value 绑定属性值,并用 @input 事件监听输入并赋值,例如 <input :value="myValue.property" @input="myValue.property = $event.target.value">。这样输入会改变数据但不会触发更新,需要时用 forceUpdate。

Vue 2 中数组更新有哪些注意事项?

数组中的对象可以按对象的方式处理。数组本身可以通过整体重新赋值,或使用 push、pop、shift、unshift、splice、sort、reverse 这些被包裹的方法来触发更新。

为什么先直接赋值再用 set 也无法让属性变成响应式?

因为 set 方法对已存在的属性不会再次进行劫持。如果属性已经被直接赋值静态添加,即使再用 set,它也不会变成响应式。

v-model 和 @input + :value 在动态属性上表现有何不同?

v-model 是 @input 和 :value 的语法糖,但处理对象属性时会自动触发 set,而 @input 直接赋值不会。如果先用 @input 直接赋值,属性未被劫持,之后 v-model 的 set 也不会再劫持已存在的属性,导致无法更新。

🏷️

标签

➡️

继续阅读