响应式原理

当我们在 Vue.js 中修改响应式对象的属性时,Vue.js 会自动对修改进行追踪,并在必要时自动更新视图,这是 Vue.js 的响应式系统的核心特性。

Vue.js 的响应式系统是通过数据劫持实现的。在 Vue.js 内部,每个组件实例包含一个拦截器——observe,它可以对组件中的所有数据进行监听。当我们对组件中的数据进行修改时,observe 就会被触发,进而更新对应的视图。这种数据劫持的机制,是依靠 Object.defineProperty 这个 API 实现的。Object.defineProperty 方法可以劫持一个对象,并在对象的 getter 和 setter 被访问时,拦截它们的访问以实现数据劫持。

对于修改对象属性或数组元素,Vue.js 会通过 Vue.set()Vue.delete() 方法来实现响应式更新。当我们通过直接修改数组索引的方式更新数组时,例如:this.list[1] = {name: '小美', age: 18}。这种方式虽然也能生效,但 Vue.js 无法检测到该变更。因为 Vue.js 的追踪机制是在对象初始化时,将对象的数据转换成 getter 和 setter 的形式,并对它们进行监听。因此,如果我们没有使用 Vue.set()Vue.delete() 方法实现更新,Vue.js 就无法发现变化。

使用 Vue.set()Vue.delete() 方法会通知 Vue.js 进行更新视图。这两个方法内部都是通过调用响应式对象的 __ob__ 观测者(Observer)的 dep 通知依赖这个属性的所有 watcher 更新视图。

使用 Vue.set() 方法修改数组或对象属性时会给要修改的对象的属性值,包括新增的属性,上下文对象添加一个响应式标记。同时,当我们向一个对象上添加一个不存在的新属性时,会在该对象上使用 Vue.set() 方法来触发响应式更新。在执行 Vue.set() 方法时,它会根据传入的数据源、具体数据及要赋的值,将其中符合条件的数据添加上响应式标记。当数据源中的已有属性值发生变化时,这个响应式标记会被触发,通知绑定了这个数据的组件更新对应的视图。

强制更新

在 Vue 中,当我们需要强制更新组件时,99.9% 的情况都是因为在某个地方出现了问题。可能是因为我们没有注意到响应式对象的变更检测注意事项,或者依赖了一个未被 Vue 的响应式系统追踪的状态。

如果我们已经注意到了上述的问题并修复了,但仍然需要手动强制更新时,我们可以使用 $forceUpdate() 方法。代码如下:

this.$forceUpdate()

更新响应式对象

Vue.set() 方法可以向响应式对象中添加一个新的 property,并确保这个新 property 同样是响应式的,且能触发视图更新。Vue.set() 方法必须用于向响应式对象上添加新 property,因为 Vue 无法探测普通的新增 property(比如 this.myObject.newProperty = ‘hi’)。

调用 Vue.set() 方法的语法为:this.$set(target, key, value)。其中:

  • target:要更改的数据源,可以是对象或数组。
  • key:要更改的具体数据。
  • value:重新赋的值。

以下是几种使用 Vue.set() 方法的示例:

data() {
  return {
    list: [
      {
        name: '小明',
        age: 18
      },
      {
        name: '小美',
        age: 12
      }
    ],
    text: '我是未修改的字符串值'
  }
}

// 修改列表中小美的所有数据
this.$set(this.list, 1, {
  name: '小美',
  age: 18
})

// 修改列表中小美的年龄为18岁
this.$set(this.list[1], 'age', 18)

// 修改某个字符串属性
this.$set(this, 'text', '我是修改后的字符串值')

通过以上例子我们可以看到,Vue.set() 方法在修改响应式对象时非常实用。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐