/* @flow */
|
|
import config from '../config'
|
import { initProxy } from './proxy'
|
import { initState } from './state'
|
import { initRender } from './render'
|
import { initEvents } from './events'
|
import { mark, measure } from '../util/perf'
|
import { initLifecycle, callHook } from './lifecycle'
|
import { initProvide, initInjections } from './inject'
|
import { extend, mergeOptions, formatComponentName } from '../util/index'
|
|
let uid = 0
|
|
export function initMixin (Vue: Class<Component>) {
|
Vue.prototype._init = function (options?: Object) {
|
const vm: Component = this
|
// a uid
|
vm._uid = uid++
|
|
let startTag, endTag
|
/* istanbul ignore if */
|
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
|
startTag = `vue-perf-start:${vm._uid}`
|
endTag = `vue-perf-end:${vm._uid}`
|
mark(startTag)
|
}
|
|
// a flag to avoid this being observed
|
vm._isVue = true
|
// merge options
|
if (options && options._isComponent) {
|
// optimize internal component instantiation
|
// since dynamic options merging is pretty slow, and none of the
|
// internal component options needs special treatment.
|
initInternalComponent(vm, options)
|
} else {
|
vm.$options = mergeOptions(
|
resolveConstructorOptions(vm.constructor),
|
options || {},
|
vm
|
)
|
}
|
/* istanbul ignore else */
|
if (process.env.NODE_ENV !== 'production') {
|
initProxy(vm)
|
} else {
|
vm._renderProxy = vm
|
}
|
// expose real self
|
vm._self = vm
|
initLifecycle(vm)
|
initEvents(vm)
|
initRender(vm)
|
callHook(vm, 'beforeCreate')
|
initInjections(vm) // resolve injections before data/props
|
initState(vm)
|
initProvide(vm) // resolve provide after data/props
|
callHook(vm, 'created')
|
|
/* istanbul ignore if */
|
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
|
vm._name = formatComponentName(vm, false)
|
mark(endTag)
|
measure(`vue ${vm._name} init`, startTag, endTag)
|
}
|
|
if (vm.$options.el) {
|
vm.$mount(vm.$options.el)
|
}
|
}
|
}
|
|
export function initInternalComponent (vm: Component, options: InternalComponentOptions) {
|
const opts = vm.$options = Object.create(vm.constructor.options)
|
// doing this because it's faster than dynamic enumeration.
|
const parentVnode = options._parentVnode
|
opts.parent = options.parent
|
opts._parentVnode = parentVnode
|
|
const vnodeComponentOptions = parentVnode.componentOptions
|
opts.propsData = vnodeComponentOptions.propsData
|
opts._parentListeners = vnodeComponentOptions.listeners
|
opts._renderChildren = vnodeComponentOptions.children
|
opts._componentTag = vnodeComponentOptions.tag
|
|
if (options.render) {
|
opts.render = options.render
|
opts.staticRenderFns = options.staticRenderFns
|
}
|
}
|
|
export function resolveConstructorOptions (Ctor: Class<Component>) {
|
let options = Ctor.options
|
if (Ctor.super) {
|
const superOptions = resolveConstructorOptions(Ctor.super)
|
const cachedSuperOptions = Ctor.superOptions
|
if (superOptions !== cachedSuperOptions) {
|
// super option changed,
|
// need to resolve new options.
|
Ctor.superOptions = superOptions
|
// check if there are any late-modified/attached options (#4976)
|
const modifiedOptions = resolveModifiedOptions(Ctor)
|
// update base extend options
|
if (modifiedOptions) {
|
extend(Ctor.extendOptions, modifiedOptions)
|
}
|
options = Ctor.options = mergeOptions(superOptions, Ctor.extendOptions)
|
if (options.name) {
|
options.components[options.name] = Ctor
|
}
|
}
|
}
|
return options
|
}
|
|
function resolveModifiedOptions (Ctor: Class<Component>): ?Object {
|
let modified
|
const latest = Ctor.options
|
const sealed = Ctor.sealedOptions
|
for (const key in latest) {
|
if (latest[key] !== sealed[key]) {
|
if (!modified) modified = {}
|
modified[key] = latest[key]
|
}
|
}
|
return modified
|
}
|