接上文 [0x030-Vue2-6源码阅读1-项目结构和初始化],观察一下 Vue.component
的初始化:
Vue.component
的使用方法
Vue.component() 是 Vue.js 中用于全局注册组件的一个方法。通过使用它,我们可以在 Vue 应用程序的任何地方使用该组件。
使用示例:
- 在 Vue 根实例中注册组件:
javascript
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button @click="count++">
You clicked me {{ count }} times.
</button>'
})
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button @click="count++">
You clicked me {{ count }} times.
</button>'
})
- 在组件中使用这个全局注册的组件:
html
<template>
<div id="app">
<button-counter></button-counter>
</div>
</template>
<template>
<div id="app">
<button-counter></button-counter>
</div>
</template>
初始化
src/core/global-api/assets.js
ts
export const ASSET_TYPES = [
'component',
'directive',
'filter'
]
export function initAssetRegisters (Vue: GlobalAPI) {
ASSET_TYPES.forEach(type => {
Vue[type] = function (id: string, definition: Function | Object): Function | Object | void {
if (!definition) {
return this.options[type + 's'][id]
} else {
if (type === 'component' && isPlainObject(definition)) {
definition.name = definition.name || id
definition = this.options._base.extend(definition)
}
if (type === 'directive' && typeof definition === 'function') {
definition = { bind: definition, update: definition }
}
this.options[type + 's'][id] = definition
return definition
}
}
})
}
export const ASSET_TYPES = [
'component',
'directive',
'filter'
]
export function initAssetRegisters (Vue: GlobalAPI) {
ASSET_TYPES.forEach(type => {
Vue[type] = function (id: string, definition: Function | Object): Function | Object | void {
if (!definition) {
return this.options[type + 's'][id]
} else {
if (type === 'component' && isPlainObject(definition)) {
definition.name = definition.name || id
definition = this.options._base.extend(definition)
}
if (type === 'directive' && typeof definition === 'function') {
definition = { bind: definition, update: definition }
}
this.options[type + 's'][id] = definition
return definition
}
}
})
}
简化下component
的代码:
js
Vue.component = function (
id: string,
definition: Function | Object
): Function | Object | void {
if (!definition) {
// 没有definition的时候,返回定义的组件
return this.options[type + 's'][id]
} else {
// 如果没有名字, definition.name = id
definition.name = definition.name || id;
// 调用Vue.extend扩展definition(option)
definition = this.options._base.extend(definition);
this.options.components[id] = definition
return definition
}
}
}
Vue.component = function (
id: string,
definition: Function | Object
): Function | Object | void {
if (!definition) {
// 没有definition的时候,返回定义的组件
return this.options[type + 's'][id]
} else {
// 如果没有名字, definition.name = id
definition.name = definition.name || id;
// 调用Vue.extend扩展definition(option)
definition = this.options._base.extend(definition);
this.options.components[id] = definition
return definition
}
}
}
js
export function initExtend (Vue: GlobalAPI) {
/**
* 每个实例构造函数(包括 Vue)都有一个唯一的 cid。这使我们能够创建包装的“子构造函数”以进行原型继承并缓存它们。
*/
Vue.cid = 0
let cid = 1
/**
* Class inheritance
*/
Vue.extend = function (extendOptions: Object): Function {
extendOptions = extendOptions || {}
const Super = this
// 第一次extend 进入 cid = 0
const SuperId = Super.cid
// 第一次extend 进入 cachedCtors = {}
// `_Ctor`在Vue源码中只有本function用到了。子组件options._Ctor缓存父组件的id(唯一),防止重复调用的时候重复调用后续代码
const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
if (cachedCtors[SuperId]) {
return cachedCtors[SuperId]
}
const name = extendOptions.name || Super.options.name
const Sub = function VueComponent (options) {
// 后面 new VueExtend(...)的时候调用
this._init(options)
}
Sub.prototype = Object.create(Super.prototype)
Sub.prototype.constructor = Sub
Sub.cid = cid++
Sub.options = mergeOptions(
Super.options,
extendOptions
)
Sub['super'] = Super
// For props and computed properties, we define the proxy getters on
// the Vue instances at extension time, on the extended prototype. This
// avoids Object.defineProperty calls for each instance created.
if (Sub.options.props) {
initProps(Sub)
}
if (Sub.options.computed) {
initComputed(Sub)
}
// allow further extension/mixin/plugin usage
Sub.extend = Super.extend
Sub.mixin = Super.mixin
Sub.use = Super.use
// 将component等等函数也挂载到子组件
ASSET_TYPES.forEach(function (type) {
Sub[type] = Super[type]
})
// enable recursive self-lookup
if (name) {
Sub.options.components[name] = Sub
}
// keep a reference to the super options at extension time.
// later at instantiation we can check if Super's options have
// been updated.
Sub.superOptions = Super.options
Sub.extendOptions = extendOptions
Sub.sealedOptions = extend({}, Sub.options)
// cache constructor
cachedCtors[SuperId] = Sub
return Sub
}
}
export function initExtend (Vue: GlobalAPI) {
/**
* 每个实例构造函数(包括 Vue)都有一个唯一的 cid。这使我们能够创建包装的“子构造函数”以进行原型继承并缓存它们。
*/
Vue.cid = 0
let cid = 1
/**
* Class inheritance
*/
Vue.extend = function (extendOptions: Object): Function {
extendOptions = extendOptions || {}
const Super = this
// 第一次extend 进入 cid = 0
const SuperId = Super.cid
// 第一次extend 进入 cachedCtors = {}
// `_Ctor`在Vue源码中只有本function用到了。子组件options._Ctor缓存父组件的id(唯一),防止重复调用的时候重复调用后续代码
const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
if (cachedCtors[SuperId]) {
return cachedCtors[SuperId]
}
const name = extendOptions.name || Super.options.name
const Sub = function VueComponent (options) {
// 后面 new VueExtend(...)的时候调用
this._init(options)
}
Sub.prototype = Object.create(Super.prototype)
Sub.prototype.constructor = Sub
Sub.cid = cid++
Sub.options = mergeOptions(
Super.options,
extendOptions
)
Sub['super'] = Super
// For props and computed properties, we define the proxy getters on
// the Vue instances at extension time, on the extended prototype. This
// avoids Object.defineProperty calls for each instance created.
if (Sub.options.props) {
initProps(Sub)
}
if (Sub.options.computed) {
initComputed(Sub)
}
// allow further extension/mixin/plugin usage
Sub.extend = Super.extend
Sub.mixin = Super.mixin
Sub.use = Super.use
// 将component等等函数也挂载到子组件
ASSET_TYPES.forEach(function (type) {
Sub[type] = Super[type]
})
// enable recursive self-lookup
if (name) {
Sub.options.components[name] = Sub
}
// keep a reference to the super options at extension time.
// later at instantiation we can check if Super's options have
// been updated.
Sub.superOptions = Super.options
Sub.extendOptions = extendOptions
Sub.sealedOptions = extend({}, Sub.options)
// cache constructor
cachedCtors[SuperId] = Sub
return Sub
}
}
由定义过程(this._init(options)
)可以知道调用this._init(options)
的不仅有父组件还是子组件
组件初始化代码
代码位置:
js
export function createComponentInstanceForVnode (
// we know it's MountedComponentVNode but flow doesn't
vnode: any,
// activeInstance in lifecycle state
parent: any
): Component {
const options: InternalComponentOptions = {
_isComponent: true,
// 当前组件的VNode,对要创建的子组件来说是父Node
_parentVnode: vnode,
parent
}
// check inline-template render functions
const inlineTemplate = vnode.data.inlineTemplate
if (isDef(inlineTemplate)) {
options.render = inlineTemplate.render
options.staticRenderFns = inlineTemplate.staticRenderFns
}
return new vnode.componentOptions.Ctor(options)
}
export function createComponentInstanceForVnode (
// we know it's MountedComponentVNode but flow doesn't
vnode: any,
// activeInstance in lifecycle state
parent: any
): Component {
const options: InternalComponentOptions = {
_isComponent: true,
// 当前组件的VNode,对要创建的子组件来说是父Node
_parentVnode: vnode,
parent
}
// check inline-template render functions
const inlineTemplate = vnode.data.inlineTemplate
if (isDef(inlineTemplate)) {
options.render = inlineTemplate.render
options.staticRenderFns = inlineTemplate.staticRenderFns
}
return new vnode.componentOptions.Ctor(options)
}