Vue 响应式原理
一、前言
vue 响应式原理是数据渲染到视图,及数据修改触发视图更新的过程。
二、原理
1、数据监听
当把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty
为这些属性设置 getter/setter。
这些 getter/setter 对用户来说不可见,但是在内部它们让 Vue 能够追踪依赖,在属性被访问和修改时通知变更。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| function defineReactive(obj: Object, key: string, ...) { var dep = new Dep()
Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function reactiveGetter () { dep.depend() return value }, set: function reactiveSetter (newVal) { val = newVal dep.notify() } }) }
|
2、依赖收集
每个组件在渲染的过程中都会创建一个对应的 watcher(订阅者) 实例,创建 watcher 实例时会去进行模版解析,会触发属性的 getter,而每个属性在最开始设置 setter/getter 时会建立一个与之对应的收集器, getter 的调用会让该收集器记录当前的 watcher 实例,以便于之后属性变化的时候能通知到它。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| export default class Watcher { constructor (vm: Component, expOrFn: string | Function, cb: Function, ...) { this.cb = cb this.getter = expOrFn this.value = this.get() }
get () { Dep.target = target value = this.getter.call(this.vm, this.vm) Dep.target = null return value }
addDep (dep: Dep) { dep.addSub(this) }
update () { this.run() }
run () { const oldValue = this.value const value = this.get() this.cb.call(this.vm, value, oldValue) } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| export default class Dep { static target: ?Watcher; id: number; subs: Array<Watcher>;
constructor () { this.id = uid++ this.subs = [] }
addSub (sub: Watcher) { this.subs.push(sub) }
removeSub (sub: Watcher) { remove(this.subs, sub) }
depend () { if (Dep.target) { Dep.target.addDep(this) } }
notify () { const subs = this.subs.slice() for (let i = 0, l = subs.length; i < l; i++) { subs[i].update() } } } }
|
3、派发更新
当属性被修改时,会触发属性的 setter
,然后该属性的收集器会遍历当前的所有 watcher 实例并发送通知,watcher 实例会去执行自己的 update()
方法,触发组件的重新渲染,再次去触发属性的 getter。
参考链接
https://cn.vuejs.org/v2/guide/reactivity.html
微信打赏