以下是Vue结构申明外围代码,是跨平台共用的外围代码,为什么说跨平台共用呢,这里次要指的是不同平台(web和weex)在vue.prototype上还会丰盛本人的个性(属性和办法),如比拟重要的__patch__办法、以及平台特定的组件和指令。
import { initMixin } from './init'import { stateMixin } from './state'import { renderMixin } from './render'import { eventsMixin } from './events'import { lifecycleMixin } from './lifecycle'import { warn } from '../util/index'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)export default Vue
其中各种Mixin次要是丰盛原型链上的属性或办法:
initMixin: 申明vue.prototype.init,前面会细看,见原型init
stateMixin: 申明vue.prototype.[$data | $props]属性,以及$set、$delete、$watch办法
eventsMixin: 申明vue.prototype.[$on | $off | $once | $emit]办法,让vm本身取得了事件的注册触发能力
lifecycleMixin: 申明vue.prototype.[_update | $forceUpdate | $destroy]办法
renderMixin: 申明vue.prototype.[_render | $nextTick]办法,以及一系列外部helpers工具函数,以(_字母)别名办法
切换到Web平台视角
先暂且只看web平台目录给vue.prototype上削减[_patch_ | $mount]办法,并且将平台特定指令和组件装置到结构Vue.options上。
原型init
其中次要局部,一部分是:
initLifecycle(vm)initEvents(vm)initRender(vm)callHook(vm, 'beforeCreate')initInjections(vm) // resolve injections before data/propsinitState(vm)initProvide(vm) // resolve provide after data/propscallHook(vm, 'created')
另一部分是:
if (vm.$options.el) { vm.$mount(vm.$options.el)}
其它蕴含vue的options的解析、合并及合并策略。
第一局部:
initLifecycle: 申明vm实例属性[$parent | $root | $children | $refs | _watcher | _inactive | _directInactive | _isMounted | _isDestroyed | _isBeingDestroyed],其中$parent会波及parent的解析和关系绑定,即在parent的$children中注册子vm
initEvents: 申明vm实例属性[_events | _hasHookEvent],以及更新组件的事件listeners或者登记事件
initRender: 申明vm实例属性[_vnode | _staticTrees | $options | $vnode | $slots | $scopedSlots | _c | $createElement | $attrs | $listeners],其中$attrs和$listeners是响应式的属性,然而浅响应的。即在
defineReactive申明时指定shallow为true
看一看defineReactive
- 肯定状况下放弃申明key原来的getter和setter的切面影响
- 通过shallow传入来管制对象该key的值是否须要持续纳入响应式治理
- 具体通过闭包Dep实例将该key纳入响应式零碎
通过dep.depend将target:[Watcher]放入本人的subs
看上去是调用watcher的addDep办法,并且该办法会判断是否曾经依赖该dep
depend () { if (Dep.target) { Dep.target.addDep(this) } }
本质上最初还是调用了dep的addSub办法
addDep (dep: Dep) { const id = dep.id if (!this.newDepIds.has(id)) { this.newDepIds.add(id) this.newDeps.push(dep) if (!this.depIds.has(id)) { dep.addSub(this) } } }
这样一来,dep中有watcher(通过subs),watcher中也有dep(通过newDepIds)
Dep类
- Dep类有一个动态属性target,代表以后watcher,全局惟一,每次只会有一个正在进行的watcher,然而指标watcher是一个栈并且有配套的入栈和出栈操作,别离对应pushTarget和popTarget,这种设计能够反对嵌套的调用和watcher解决。
- Dep类通过depend办法建设和watcher的双向关联,并且watcher关联dep是通过dep的addSub办法,反之勾销关联是通过dep的removeSub办法
- Dep类通过notify办法来告诉关联wathcer[]来进行更新及动作
- Dep代表响应式零碎中的被观察者
- 所有Dep实例对立进行Uid调配,即Uid++
Watcher类
- watcher分为renderWatcher和userWatcher,二者都会关联在vm的_watchers[]列表中,而且renderWatcher还会关联在vm的_watcher
- lazy-watcher的value会通过Watcher的evaluate设置
- Dep的notify触发watcher的update会辨别几种状况,一种是lazy的话会设置dirty的flag,如果是sync的话会间接同步执行getter并且执行cb回调,其它状况会queueWatcher
- Watcher的get执行在执行初始化解析的getter之前会pushTarget,这样在getter执行中若有相干的dep.depend,则会关联以后watcher和dep
- Watcher监听path的解析算法是简略的a.b.c属性点宰割,但解析后的后果是一个闭包
- watcher的回调执行只有在其value发生变化,或者value是对象,或者是deep时才会执行,具备肯定的惰性
- queueWatcher的算法是若watcher队列还没有被flush则增加即可,若曾经被flush了然而还没有到它,则对刚flush的待执行队列进行查找替换,否则安顿至nextTick下一波队列
- Watcher代表响应式零碎中的订阅者
- 所有Watcher实例对立进行Uid调配,即Uid++
callHook: 执行相应的钩子函数及vm本身的钩子事件监听(如vm.$on('hook:created'))
initInjections: 略
initState:
initProvide: 略
callHook: 同上