Vue 2 的响应式原理主要基于 数据劫持 和 发布-订阅模式,通过 Object.defineProperty
对对象的属性进行拦截,实现数据的监控与视图更新。具体原理如下:
1. 数据劫持:Object.defineProperty
Vue 2 在初始化过程中,通过 Object.defineProperty
给对象的每一个属性添加 getter 和 setter,来劫持数据的访问和修改。
- getter: 当访问该属性时,Vue 会触发
getter
,在这个过程中 Vue 会将当前的 watcher(即视图中的依赖)收集到该属性的依赖列表中。这样,当该属性发生变化时,相关的视图就能知道并做出更新。 - setter: 当修改该属性的值时,Vue 会触发
setter
,然后触发依赖更新(通过通知 watcher 进行视图的重新渲染)。
2. 依赖收集:Dep
和 Watcher
Vue 2 中使用了 Dep 和 Watcher 对象来实现依赖收集和视图更新:
-
Dep: 每个数据属性(通过
Object.defineProperty
劫持的属性)都会有一个对应的Dep
对象,负责管理该属性的所有依赖(即需要观察该属性的视图、计算属性等)。当该数据发生变化时,Dep
会通知所有依赖该属性的 watcher 进行更新。 -
Watcher: 在 Vue 组件中,每个组件实例都对应着一个
Watcher
,它会监听模板中使用到的响应式数据。Watcher
会在数据发生变化时进行相应的视图更新。
3. 发布-订阅模式
- 发布者: 数据对象通过
Object.defineProperty
拦截属性的访问和修改,作为发布者。 - 订阅者: 视图(
watcher
)和计算属性等是订阅者,它们会在数据变化时进行相应的更新。通过Dep
,每当数据发生变化时,Dep
会通知所有相关的watcher
,从而触发视图更新。
4. 视图更新
当数据发生变化时,setter
会触发 Dep
的通知机制,Dep
会遍历所有依赖它的 watcher
,然后更新视图。Vue 会通过 虚拟 DOM 比对前后差异(即 diff 算法),然后将差异应用到实际的 DOM 上,从而实现视图的更新。
总结
- Vue 2 通过
Object.defineProperty
劫持数据的 getter 和 setter,来监听数据的访问和修改。 - 使用 Dep 和 Watcher 实现 依赖收集 和 视图更新。
- 视图变化时,
watcher
触发更新,通过 虚拟 DOM 和 diff 算法 优化性能,最终更新真实 DOM。
Vue 2 的响应式系统基于数据劫持和发布-订阅模式,提供了数据和视图的双向绑定机制,简化了开发过程中的 DOM 操作。