tips:本系列博客的代码部分(示例等除外),均出自vue源码内容,版本为2.6.14。但是为了增加易读性,会对不相关内容做选择性省略。如果大家想了解完整的源码,建议自行从官方下载。
本系列博客 ( 不定期更新 ):
【VUE】源码分析 - computed计算属性的实现原理_依然范特西fantasy的博客-优快云博客
【VUE】源码分析 - watch侦听器的实现原理_依然范特西fantasy的博客-优快云博客
【VUE】源码分析 - 数据劫持的基本原理_依然范特西fantasy的博客-优快云博客
进入正题
我们都知道,Vue 提供了一种方式来观察和响应 Vue 实例上的数据变动:侦听属性。那么其具体的实现原理是什么呢?
首先从vue初始化的地方出发:
function Vue (options) {
if (process.env.NODE_ENV !== 'production' &&
!(this instanceof Vue)
) {
warn('Vue is a constructor and should be called with the `new` keyword')
}
this._init(options)
}
initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)
可以看到,vue其实就是一个构造函数。在创建vue实例的时候,会根据传入的options做_init初始化处理。当然,在未初始化之前,就需要将一些必要的实例方法、属性等准备好。Vue构造函数下面的几个mixin文件,就类似一个个的"加工车间",将Vue层层包装,提前准备好所有需要的方法和属性。
而我们现在所研究的watch属性 ( watch属性的最终实现其实应该是$watch实例方法 ),就存放在stateMixin这个"车间"内。
$watch的初步分析
Vue.prototype.$watch = function (
expOrFn: string | Function,
cb: any,
options?: Object
): Function {
const vm: Component = this
if (isPlainObject(cb)) {
return createWatcher(vm, expOrFn, cb, options)
}
options = options || {}
options.user = true
const watcher = new Watcher(vm, expOrFn, cb, options)
if (options.immediate) {
const info = `callback for immediate watcher "${watcher.expression}"`
pushTarget()
invokeWithErrorHandling(cb, vm, [watcher.value], vm, info)
popTarget()
}
return function unwatchFn () {
watcher.teardown()
}
}