通过数据劫持set发布消息,通过watcher进行订阅消息,从而触发update
代码1
export class Observer {
...
constructor (value: any) {
this.value = value
this.dep = new Dep()
this.vmCount = 0
...
}
代码2
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
const value = getter ? getter.call(obj) : val
if (Dep.target) {
dep.depend() //watcher放入dep.subs中
...
}
return value
},
...
})
代码3
Vue.prototype.$mount = function (
el?: string | Element,
hydrating?: boolean
): Component {
el = el && inBrowser ? query(el) : undefined
return mountComponent(this, el, hydrating)
}
代码4
get () {
pushTarget(this) //watcher放入Dep.target中
let value
const vm = this.vm
try {
value = this.getter.call(vm, vm) // 执行getter
} catch (e) {
if (this.user) {
handleError(e, vm, `getter for watcher "${this.expression}"`)
} else {
throw e
}
}
...
return value
}
代码5
function initComputed (vm: Component, computed: Object) {
// $flow-disable-line
const watchers = vm._computedWatchers = Object.create(null) // 同一个引用
// computed properties are just getters during SSR
const isSSR = isServerRendering()
for (const key in computed) {
const userDef = computed[key]
const getter = typeof userDef === 'function' ? userDef : userDef.get
if (process.env.NODE_ENV !== 'production' && getter == null) {
warn(
`Getter is missing for computed property "${key}".`,
vm
)
}
if (!isSSR) {
// create internal watcher for the computed property.
watchers[key] = new Watcher( //放入computedWatchers中
vm,
getter || noop,
noop,
)
}
...
}
}
代码6
update () {
/* istanbul ignore else */
if (this.lazy) {
this.dirty = true
} else if (this.sync) {
this.run()
} else {
queueWatcher(this)
}
}
代码7
function createComputedGetter (key) {
return function computedGetter () {
const watcher = this._computedWatchers && this._computedWatchers[key]
if (watcher) {
if (watcher.dirty) {
watcher.evaluate() // 更新watcher.value并设置dirty为false
}
if (Dep.target) {
watcher.depend()
}
return watcher.value
}
}
}