Vue 源码
你想要的 vue 源码分析 · 12
组件注册的使用场景有两种: , 全局注册 局部注册 局部组件与全局的组件的区别 全局组件是扩展到 Vue.options 下,所有组件创建的过程中,都会从全局的 Vue.options.components 扩展到当前组件的 vm.$options.components,这就是全局组件能在全局使用的原因,局部注册是注册在 Sub.option 扩展。
组件注册的使用场景有两种: , 全局注册 局部注册 局部组件与全局的组件的区别 全局组件是扩展到 Vue.options 下,所有组件创建的过程中,都会从全局的 Vue.options.components 扩展到当前组件的 vm.$options.components,这就是全局组件能在全局使用的原因,局部注册是注册在 Sub.option 扩展。
组件注册的使用场景有两种:
全局注册,局部注册
// 这是一个全局注册的例子
Vue.component('my-component', {
// 选项
});
// src/core/global-api/assets.js
export const ASSET_TYPES = ['component', 'directive', 'filter'];
export function initAssetRegisters(Vue: GlobalAPI) {
// 遍历ASSET_TYPES 得到type后挂载到Vue上
ASSET_TYPES.forEach((type) => {
Vue[type] = function(id: string, definition: Function | Object): Function | Object | void {
if (!definition) {
return this.options[type + 's'][id];
} else {
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && type === 'component') {
validateComponentName(id);
}
// 如果type 是component 并且definition 是一个对象
if (type === 'component' && isPlainObject(definition)) {
definition.name = definition.name || id;
// 相当于Vue.extend,把这个对象转换成一个继承于Vue的构造函数 this.options._base=Vue
definition = this.options._base.extend(definition);
}
if (type === 'directive' && typeof definition === 'function') {
definition = { bind: definition, update: definition };
}
// 然后挂载在Vue.options.components上
// 每个组件的创建都是通过Vue.extend继承而来,最终将会把Vue.options合并到Sub.options,也就是组件options上
// 然后在组件实例化阶段,会执行merge options,把Sub.options.components合并到vm.$options.components
// 在创建vnode的过程中,会执行_creatElement方法
this.options[type + 's'][id] = definition;
return definition;
}
};
});
}
// src/core/vdom/create-element.js
export function _createElement(context: Component, tag?: string | Class<Component> | Function | Object, data?: VNodeData, children?: any, normalizationType?: number): VNode | Array<VNode> {
// ...
let vnode, ns;
if (typeof tag === 'string') {
let Ctor;
ns = (context.$vnode && context.$vnode.ns) || config.getTagNamespace(tag);
if (config.isReservedTag(tag)) {
// 创建一个普通vnoode
vnode = new VNode(config.parsePlatformTagName(tag), data, children, undefined, undefined, context);
//在执行完resolveAsset后,拿到组件的构造函数
} else if (isDef((Ctor = resolveAsset(context.$options, 'components', tag)))) {
// 作为createComponent 的钩子的参数
vnode = createComponent(Ctor, data, context, children, tag);
} else {
// 创建一个不认识的vnode
vnode = new VNode(tag, data, children, undefined, undefined, context);
}
} else {
// direct component options / constructor
vnode = createComponent(tag, data, context, children);
}
// ...
}
// src\core\util\options.js
export function resolveAsset(options: Object, type: string, id: string, warnMissing?: boolean): any {
/* istanbul ignore if */
if (typeof id !== 'string') {
return;
}
// 先获取到assets type为components
const assets = options[type];
// 再获取到assets[id]
if (hasOwn(assets, id)) return assets[id];
const camelizedId = camelize(id);
// 如果id不存在,把id变成驼峰形式
if (hasOwn(assets, camelizedId)) return assets[camelizedId];
const PascalCaseId = capitalize(camelizedId);
// 如果还不存在,就查一下驼峰基础上首字母也大写看存在不
if (hasOwn(assets, PascalCaseId)) return assets[PascalCaseId];
// 如果还不存在,就从原型中找
const res = assets[id] || assets[camelizedId] || assets[PascalCaseId];
// 找不到
if (process.env.NODE_ENV !== 'production' && warnMissing && !res) {
warn('Failed to resolve ' + type.slice(0, -1) + ': ' + id, options);
}
return res;
}
// vue实例化时合并option,把component合并到vm.$options.components上
Sub.prototype = Object.create(Super.prototype);
Sub.prototype.constructor = Sub;
Sub.cid = cid++;
Sub.options = mergeOptions(Super.options, extendOptions);
// 这时候就能在resolveAsset的时候拿到组件的构造函数,作为createComponent的钩子参数
// 局部注册的核心是:初始化合并option,拿到组件的构造函数,然后createElement
import HelloWorld from './components/HelloWorld';
export default {
components: {
HelloWorld
}
};
全局组件是扩展到 Vue.options 下,所有组件创建的过程中,都会从全局的 Vue.options.components 扩展到当前组件的 vm.$options.components,这就是全局组件能在全局使用的原因,局部注册是注册在 Sub.option 扩展。
暂无评论
确认操作
请再次确认编辑图片
待上传图片 (剩余 0 张)
项目详情
确认评论邮箱
邀请制评论