转自:https://www.jianshu.com/p/90b762f1f649
架构图
先看下Vue源码的基本架构图:
![](http://upload-images.jianshu.io/upload_images/1975863-7e4d072c97f8ae91.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/700)
vue源码结构.png
Vue的设计可以概括成两部分:响应式数据和节点挂载。简单来讲,前者是设计数据的getter和setter方法,保证get和set时触发视图的更新;后者是解析视图的结构,生成相应的directive(指令),视图的更新是由directive完成的。
响应式数据
Vue进行实例化时,会执行_init
函数,_init
包括了以下几个执行步骤:
Vue.prototype._initState = function () {
this._initProps()
this._initMeta()
this._initMethods()
this._initData()
this._initComputed()
}
_initProps
处理props属性,在Component中会使用到props属性_initMeta
处理诸如$index, $key & $value
等meta信息_initMethods
把methods属性中包含的方法绑定到Vue实例上,并且指定其作用域为该Vue的实例_initData
给数据的每个字段添加响应逻辑,数据获取(getter)时会更新依赖,数据设置(setter)时会通知依赖进行更新_initComputed
computed属性中方法的执行和计算,同时生成Watcher实例,Watcher负责关联数据和directive
_initData
_initData
的主要功能是给data中所有字段都加上响应式设计。当字段进行get操作时,更新订阅当前字段的Watcher对象,也就是更新依赖;当字段set时,通知Watcher对象,Watcher对象会通知directive对象进行进行View的改变。 Watcher在数据(data)和指令(directive)之间充当数据桥梁的作用。它的主要逻辑集中在defineReactive函数:
function defineReactive (obj, key, val) {
var dep = new Dep() // dep对象负责维护订阅列表(对数据而言,就是Watcher对象)
...
var childOb = observe(val) // 迭代遍历执行
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
var value = getter ? getter.call(obj) : val
if (Dep.target) { // Dep.target是个Watcher对象实例
dep.depend() // 把Dep.target这个Watcher对象加入到dep的subs列表中
if (childOb) { // 迭代更新字段的子字段
childOb.dep.depend()
}
...
}
return value
},
set: function reactiveSetter (newVal) {
var value = getter ? getter.call(obj) : val
if (newVal === value) {
return
}
if (setter) {
setter.call(obj, newVal)
} else {
val = newVal
}
childOb = observe(newVal)
// 此处会调用依赖列表的watcher进行数据视图的同步!
// watcher会调用directive的更新方法
dep.notify()
}
})
}
挂载节点
普通节点
节点的挂载主要逻辑在在_compile
中,它对挂载的root节点和子节点分开处理。 对root节点,执行的流程:
_compile -> compileRoot -> compileDirectives -> vm._bindDir -> directive._bind
vm._bindDir
会依据节点的指令生成directive对象实例,然后调用directive的_bind方法实现directive和Watcher的关联:
Directive.prototype._bind = function () {
var name = this.name
var descriptor = this.descriptor
// initial bind
// 调用directive 如 on click的bind方法
if (this.bind) {
this.bind()
}
...
// 生成watcher对象,watcher对象实例化时 会执行get方法 进行一次数据的依赖收集
var watcher = this._watcher = new Watcher(
this.vm,
this.expression,
this._update, // callback
{
filters: this.filters,
twoWay: this.twoWay,
deep: this.deep,
preProcess: preProcess,
postProcess: postProcess,
scope: this._scope
}
)
// v-model with inital inline value need to sync back to
// model instead of update to DOM on init. They would
// set the afterBind hook to indicate that.
if (this.afterBind) {
this.afterBind()
} else if (this.update) {
this.update(watcher.value)
}
}
this._bound = true
}
对于非root节点,有一个迭代遍历解析的过程,基本的执行过程相同。
Component节点
对了组件(Component)中的逻辑,其执行流程和普通的节点相似;不同的地方是它有一个独立的作用域。
作者:狐尼克朱迪
链接:https://www.jianshu.com/p/90b762f1f649
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。