Vue的双向数据绑定原理

101 阅读3分钟

Vue 的双向数据绑定是其核心特性之一,使得数据的变化能够自动吧更新到试图,视图的变化也能自动更新到数据。

vue2 双向数据绑定原理

vue2 的双向数据绑定主要基于 数据劫持 结合 发布-订阅者模式 实现,并且在模版编译过程中完成视图和数据的关联。

1.1 数据劫持

Vue2 使用Object.defineProperty() 方法对数据对象的属性进行劫持,当这些属性的值发生变化的时,会触发相应的 gettersetter方法。

1.2 发布者 - 订阅者模式

  • Dep 类(依赖收集器) :每个数据属性都有一个对应的 Dep 实例,用于收集依赖和通知订阅者。当属性的 getter 方法被调用时,会将当前的订阅者添加到 Dep 实例的订阅者列表中;当属性的 setter 方法被调用时,会通知所有订阅者更新。

  • Watcher 类(订阅者) :表示一个订阅者,当数据发生变化时,会调用 update 方法更新视图。

1.3. 模板编译

Vue 在实例初始化时会对模板进行编译,将模板中的指令和表达式解析成对应的渲染函数。在编译过程中,会为每个绑定了数据的 DOM 元素创建一个 Watcher 实例,该实例会在数据变化时更新对应的 DOM 元素。

1.4. 整体流程

  1. 初始化数据:创建 Vue 实例时,传入数据对象,使用 observe 函数对数据对象进行劫持。
  2. 模板编译:对模板进行编译,解析指令和表达式,为每个绑定了数据的 DOM 元素创建 Watcher 实例。
  3. 依赖收集:在 Watcher 实例的 get 方法中,将当前的 Watcher 实例赋值给 Dep.target,然后读取数据属性,触发属性的 getter 方法,将 Dep.target 添加到 Dep 实例的订阅者列表中。
  4. 数据更新:当数据属性的值发生变化时,触发属性的 setter 方法,调用 Dep 实例的 notify 方法通知所有订阅者更新。
  5. 视图更新Watcher 实例收到通知后,调用 update 方法更新对应的 DOM 元素。

vue3 双向数据绑定的原理

Vue3 使用 Proxy 对象来实现数据劫持,结合 ReactiveEffect 来管理依赖和更新,整体思路与 Vue2 类似,但更加高效灵活。

2.1 Proxy 数据劫持

Proxy 是 ES6 引入的新特性,它可以对整个对象进行代理,能够拦截对象的各种操作,包括属性的读取、赋值、删除等。

2.2 ReactiveEffect 管理依赖

Vue 3 引入了 ReactiveEffect 来管理依赖和更新。当一个 ReactiveEffect 运行时,会收集它所依赖的响应式数据,当这些数据发生变化时,会重新运行该 ReactiveEffect

2.3. 整体流程

  1. 创建响应式对象:使用 reactive 或 ref 函数创建响应式对象,内部使用 Proxy 进行数据劫持。
  2. 依赖收集:当 ReactiveEffect 运行时,读取响应式对象的属性,触发 Proxy 的 get 拦截器,收集依赖。
  3. 数据更新:当响应式对象的属性发生变化时,触发 Proxy 的 set 拦截器,通知所有依赖该属性的 ReactiveEffect 重新运行。
  4. 视图更新ReactiveEffect 重新运行时,会更新对应的 DOM 元素。

综上所述,Vue2 和 Vue3 的双向数据绑定原理核心都是数据劫持和依赖管理,但实现方式上有所不同,Vue3 利用 Proxy 解决了 Vue 2 中 Object.defineProperty() 的一些局限性。