Vue入口
Vue的入口是在src/core/instance/index.js中,它的真身就是一个Function。
在此文件中还进行了一系列的初始化操作:
-
initMinxin:在Vue原型上定义了_init方法。_init方法在new Vue()时会调用,用来初始化。
-
stateMixin:在Vue原型上定义了$data和$props两个实例属性。并定义了$del、$set、$watch实例方法。
-
eventsMinin:在Vue原型上定义了$on、$once、$off、$emit实例方法。
-
lifecycleMixin:在Vue原型上定义_update、$forceUpdate、$destroy实例方法。
-
renderMixin:在Vue原型上定义了_render、$nextTick实例方法。
在src/core/global-api/index.js中,通过initGlobalAPI()方法,给 Vue 这个对象本身扩展全局的静态方法。
_init初始化
此方法在initMinxin(Vue)中挂载到Vue原型,并在new Vue()时调用。
Vue.prototype._init = function (options?: Object) {
const vm: Component = this
vm._uid = uid++
vm._isVue = true
if (options && options._isComponent) {
initInternalComponent(vm, options)
} else {
vm.$options = mergeOptions(
resolveConstructorOptions(vm.constructor),
options || {},
vm
)
}
if (process.env.NODE_ENV !== 'production') {
initProxy(vm)
} else {
vm._renderProxy = vm
}
vm._self = vm
initLifecycle(vm)
initEvents(vm)
initRender(vm)
callHook(vm, 'beforeCreate')
initInjections(vm)
initState(vm)
initProvide(vm)
callHook(vm, 'created')
if (vm.$options.el) {
vm.$mount(vm.$options.el)
}
}
每个vue实例都有一个_uid,并且是依次递增的。根据_isComponent判断是子组件还是根组件。对于自组件通过initInternalComponent来进行优化,减少原型链查找配置。对于根组件通过mergeOptions 处理组件配置项,这里将用户传递的options选项与当前构造函数的options属性及其父级实例构造函数的options合并生成一个新的options赋值给$options。然后设置代理,将vm实例上的属性代理到vm._renderProxy。接着进行一系列初始化:
-
initLifecycle:初始化vm.$parent、vm.$root、vm.$children、vm.$refs等属性值。
-
initEvents:初始化事件中心:vm._events = Object.create(null)。
-
initRender:初始化渲染定义vm._c(用于用户使用template模式) vm.$createElement(用于用户手写render函数)。
-
callHook(vm, 'beforeCreate'):生命周期beforeCreate 。
-
initInjections:初始化inject。
-
initState:初始化 data, props, methods, computed, watch 等等。响应式就是这里处理的。
-
initProvide:初始化provide。
-
callHook(vm, 'created'):生命周期created。
如果发现配置项上有el选项,则自动调用$mount方法,也就是说有了el选项,就不需要再手动调用$mount,反之,没有el则必须手动调用$mount。
initLifecycle
function initLifecycle (vm: Component) {
const options = vm.$options
let parent = options.parent
if (parent && !options.abstract) {
while (parent.$options.abstract && parent.$parent) {
parent = parent.$parent
}
parent.$children.push(vm)
}
vm.$parent = parent
vm.$root = parent ? parent.$root : vm
vm.$children = []
vm.$refs = {}
vm._watcher = null
vm._inactive = null
vm._directInactive = false
vm._isMounted = false
vm._isDestroyed = false
vm._isBeingDestroyed = false
}
如果当前组件不是抽象组件,并且$options存在parent,那么将不断向上层查找直到找到非抽象类的父级(例如keep-alive组件就是抽象类),然后赋值给$parent属性。并且将自己添加到父级的$children属性中。如果当前组件没有父级,那么它自己就是根组件,也就是$root就是它本身。如果存在父级,那么它的$root就沿用父级的$root。然后定义一系列属性的默认值。
initEvents
function initEvents (vm: Component) {
vm._events = Object.create(null)
vm._hasHookEvent = false
const listeners = vm.$options._parentListeners
if (listeners) {
updateComponentListeners(vm, listeners)
}
}
这里初始化了事件系统,创建了一个用于存放事件的空对象。之后注册的事件都会存放于_events中。
在模板编译时,如果解析到组件标签,会实例化子组件。并将标签上注册的事件解析成object并通过参数传递给子组件。这些事件则保存在vm.$options._parentListeners中。当它不为空时则调用updateComponentListeners方法去注册事件。
updateComponentListeners
let target: any
function add (event, fn) {
target.$on(event, fn)
}
function remove (event, fn) {
target.$off(event, fn)
}
function createOnceHandler (event, fn) {
const _target = target
return function onceHandler () {
const res = fn.apply(null, arguments)
if (res !== null) {
_target.$off(event, onceHandler)
}
}
}
function updateComponentListeners (
vm: Component,
listeners: Object,
oldListeners: ?Object
) {
target = vm
updateListeners(listeners, oldListeners || {}, add, remove, createOnceHandler, vm)
target = undefined
}
target用于存放当前实例,add用于给当前实例注册事件,remove用于解除事件。createOnceHandler用来创建一个只调用一次的函数,当执行完这个函数会立即解绑。将这三个方法,以及用于存放旧事件的参数传入到updateListeners中。
updateListeners
function updateListeners (
on: Object,
oldOn: Object,
add: Function,
remove: Function,
createOnceHandler: Function,
vm: Component
) {
let name, def, cur, old, event
for (name in on) {
def = cur = on[name]
old = oldOn[name]
event = normalizeEvent(name)
if (isUndef(cur)) {
process.env.NODE_ENV !== 'production' && warn(
`Invalid handler for event "${event.name}": got ` + String(cur),
vm
)
} else if (isUndef(old)) {
if (isUndef(cur.fns)) {
cur = on[name] = createFnInvoker(cur, vm)
}
if (isTrue(event.once)) {
cur = on[name] = createOnceHandler(event.name, cur, event.capture)
}
add(event.name, cur, event.capture, event.passive, event.params)
} else if (cur !== old) {
old.fns = cur
on[name] = old
}
}
for (name in oldOn) {
if (isUndef(on[name])) {
event = normalizeEvent(name)
remove(event.name, oldOn[name], event.capture)
}
}
}
这里主要的逻辑就是:如果新事件对应的事件名是null或者是undefined那么就会抛出警告。如果新的事件不存在于老的事件对象中,那就通过add注册。如果事件名在on和oldOn中都存在,但是它们并不相同,则将旧事件回调替换成on中的回调,并且把on中的回调引用指向oldOn中对应的事件。如果老的事件不存在新的事件对象中,则通过remove解除。
normalizeEvent在这里的作用是为了解析真正的事件名,因为有修饰符的事件是这样的
<child v-on:increment.once="a"></child>
转换为{~increment:function(){}}
通过normalizeEvent会解析得到事件名increment。