组件注册

前言

在 Vue.js 中,除了它内置的组件如 keep-alive、component、transition、transition-group 等,其它用户自定义组件在使用前必须注册。在开发过程中可能会遇到如下报错信息:

Unknown custom element: <app> - did you register the component correctly?
For recursive components, make sure to provide the "name" option.

一般报这个错的原因都是我们使用了未注册的组件。Vue.js 提供了 2 种组件的注册方式,全局注册和局部注册。接下来我们从源码分析的角度来分析这两种注册方式。

全局注册

在初始化加载阶段会调用initAssetRegisters函数把需要注册的组件挂载到Vue.options上。

// src\core\global-api\index.js
initAssetRegisters(Vue)
// src\core\global-api\assets.js
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 {
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && type === 'component') {
validateComponentName(id)
}
if (type === 'component' && isPlainObject(definition)) {
// 优先拿name,没有则取id
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
}
}
})
}

标注①:

对ASSET_TYPES进行遍历,我们先看看遍历对象ASSET_TYPES是什么?

// src\shared\constants.js
export const ASSET_TYPES = [
'component',
'directive',
'filter'
]

其实就是存放着插件、指令、过滤器这三个分类名称的数组,这里我们只单独针对component进行分析。

标注②:

this.options._base其实是Vue,具体原因请查看之前的文章《组件的创建和patch过程》

通过Vue.extend把对象转换成构造器。

最后把definition放到this.options即Vue.options上,然后return definition。

虽然挂载到Vue.options上,但是又是什么时候会被拿去注册成真正的组件呢?

我们回顾_createElement函数:

// 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> {
...
if (typeof tag === 'string') {
//是否HTML原生标签
if (config.isReservedTag(tag)) {
...
// 标注①:resolveAsset
} else if ((!data || !data.pre) && isDef(Ctor = resolveAsset(context.$options, 'components', tag))) {
// component
vnode = createComponent(Ctor, data, context, children, tag)
} else {
...
}
}
}

标注①:resolveAsset函数做了什么?

// 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
}
const assets = options[type]
//判断配置中是否存在该组件
if (hasOwn(assets, id)) return assets[id]
const camelizedId = camelize(id)
//id转换成驼峰型判断
if (hasOwn(assets, camelizedId)) return assets[camelizedId]
const PascalCaseId = capitalize(camelizedId)
//id转换成首字母大写判断
if (hasOwn(assets, PascalCaseId)) return assets[PascalCaseId]
// fallback to prototype chain
// 原型上面找
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.options是否有定义该组件,有的话则返回,然后最后经过createComponent函数进行了组件的注册。

局部注册

局部注册其实和全局注册的几乎一样,只是它需要在此前做一个option合并:

// src\core\global-api\extend.js
Sub.options = mergeOptions(
Super.options,
extendOptions
)

关于合并的详细分析请查阅之前文章《合并配置》

由于合并配置是挂载于Sub上的,也就是说它只是一个在当前Sub作用域下的,一次这种创建方式的组件只能局部使用。

Vue2.0源码学习(6) - 组件注册的更多相关文章

  1. Vue2.0源码学习(3) - 组件的创建和patch过程

    组件化 组件化是vue的另一个核心思想,所谓的组件化就,就是说把页面拆分成多个组件(component),每个组件依赖的css.js.图片等资源放在一起开发和维护.组件是资源独立的,在内部系统中是可以 ...

  2. Vue2.0源码学习(4) - 合并配置

    合并配置 通过之前的源码学习,我们已经了解到了new Vue主要有两种场景,第一种就是在外部主动调用new Vue创建一个实例,第二个就是代码内部创建子组件的时候自行创建一个new Vue实例.但是无 ...

  3. Vue2.0源码学习(2) - 数据和模板的渲染(下)

    vm._render是怎么实现的 上述updateComponent方法调用是运行了一个函数: // src\core\instance\lifecycle.js updateComponent = ...

  4. Vue2.0源码学习(1) - 数据和模板的渲染(上)

    准备 一.首先去GitHub上把vue源码download下来,传送门:https://github.com/vuejs/vue 二.搭建一个vue-cli跑起来,用于代码调试,不看着代码动起来只看源 ...

  5. 【Spark2.0源码学习】-1.概述

          Spark作为当前主流的分布式计算框架,其高效性.通用性.易用性使其得到广泛的关注,本系列博客不会介绍其原理.安装与使用相关知识,将会从源码角度进行深度分析,理解其背后的设计精髓,以便后续 ...

  6. Spring5.0源码学习系列之浅谈BeanFactory创建

    Spring5.0源码学习系列之浅谈BeanFactory创建过程 系列文章目录 提示:Spring源码学习专栏链接 @ 目录 系列文章目录 博客前言介绍 一.获取BeanFactory主流程 二.r ...

  7. [Android FrameWork 6.0源码学习] View的重绘过程之WindowManager的addView方法

    博客首页:http://www.cnblogs.com/kezhuang/p/关于Activity的contentView的构建过程,我在我的博客中已经分析过了,不了解的可以去看一下<[Andr ...

  8. spark2.0源码学习

    [Spark2.0源码学习]-1.概述 [Spark2.0源码学习]-2.一切从脚本说起 [Spark2.0源码学习]-3.Endpoint模型介绍 [Spark2.0源码学习]-4.Master启动 ...

  9. Spring5.0源码学习系列之事务管理概述

    Spring5.0源码学习系列之事务管理概述(十一),在学习事务管理的源码之前,需要对事务的基本理论比较熟悉,所以本章节会对事务管理的基本理论进行描述 1.什么是事务? 事务就是一组原子性的SQL操作 ...

随机推荐

  1. STM32 EXTI(外部中断)

    一.EXTI 简介 EXTI(External interrupt/event controller)-外部中断/事件控制器,管理了控制器的 20个中断/事件线.每个中断/事件线都对应有一个边沿检测器 ...

  2. Unity3D开发入门教程(四)——用Lua实现组件

    五邑隐侠,本名关健昌,12年游戏生涯. 本教程以 Unity 3D + VS Code + C# + tolua 为例. 一.Lua组件基类 1.在 Assets/Lua 目录下新建com目录用于存放 ...

  3. 免费增加几个T电脑空间方法,拿去不谢

    大家好,我是咔咔 不期速成,日拱一卒 在刷吾爱时猛然间看到一篇帖子名为,免费增加几个T电脑空间方法,拿去不谢,作为一名电脑磁盘深度缺乏者,这种文章怎能逃离我的法眼. 点进去大概瞅了一眼,大致意思就是把 ...

  4. 《剑指offer》面试题07. 重建二叉树

    问题描述 输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字. 例如,给出 前序遍历 preorder = [3,9,20,15,7] 中序遍 ...

  5. Boost下载安装

    下载解压 官方地址 wget https://dl.bintray.com/boostorg/release/1.72.0/source/boost_1_72_0.tar.gz tar -zxvf b ...

  6. sort排序出现安卓与苹果系统排序不一致问题

    sort排序出现安卓与苹果系统排序不一致问题

  7. 使用AJAX请求调用出现HTTPS协议错误问题

    前言: 这又是一个可能是半路就卡机的项目,在调用ajax的时候遇到了下面的这个错. js中有个ajax请求http,url是:http//:.js就提示请求了一个不安全的脚本,在发送ajax请求时,就 ...

  8. fluentd学习笔记

    转载自http://blog.csdn.net/qq_27252133/article/details/53520416 原文https://blog.laisky.com/p/fluentd/ 最近 ...

  9. 介绍一个golang库:fastcache

    学习VictoriaMetrics源码的时候发现,VictoriaMetrics的缓存部分,使用了同一产品下的fastcache.下面分享阅读fastcache源码的的结论: 1.官方介绍 fastc ...

  10. MySQL数据类型操作(char与varchar)

    目录 一:MySQL数据类型之整型 1.整型 2.验证不同类型的int是否会空出一个存储正负号 3.增加约束条件 去除正负号(unsigned) 二:浮点型 1.浮点型 2.验证浮点型精确度 三:字符 ...