文档教程前端【免费下载链接】vue-analysis:thumbsup: Vue.js 源码分析项目地址https://gitcode.com/gh_mirrors/vu/vue-analysis点击查看免费下载导读本文基于 vue-analysis 仓库对 Vue.js 2.x 源码进行剖析聚焦「组件注册」这一核心机制为什么组件在使用前必须注册Vue.component()全局注册与组件内部components选项局部注册在源码层面有何本质差异读完本文你将掌握组件注册的完整调用链从全局 API 初始化、Vue.extend继承、mergeOptions合并到_createElement渲染时的resolveAsset解析并能据此理解「全局组件可用任意地方、局部组件仅限当前作用域」的根本原因为日常开发中的组件化决策提供源码级依据。认识组件注册与典型报错在 Vue.js 中除了内置组件如keep-alive、component、transition、transition-group等其它用户自定义组件在使用前必须注册。否则运行时渲染时就会抛出如下警告Unknown custom element: xxx - did you register the component correctly? For recursive components, make sure to provide the name option.这条报错信息的含义是模板中的xxx标签既不是平台保留标签如div、span等 HTML 原生元素也无法从当前实例的$options.components中解析到对应组件构造函数于是 Vue 将其当作未知元素处理。常见触发场景包括忘记注册组件就直接在模板中使用局部注册的子组件被放到了错误的作用域父组件无法访问子组件内部的局部注册递归组件未提供name选项导致递归自引用无法解析。Vue.js 提供了两种注册方式——全局注册Vue.component(tagName, options)与局部注册组件内部的components选项。下面从源码角度分别剖析。全局注册Vue.component的诞生与实现注册函数的定义时机initAssetRegisters要注册一个全局组件使用Vue.component(tagName, options)Vue.component(my-component, { // 选项 })那么Vue.component这个函数是什么时候被定义的呢它发生在 Vue 全局 API 初始化阶段。initGlobalAPI在 vue/src/core/global-api/index.js 中按顺序调用initUse、initMixin、initExtend、initAssetRegisters其中initAssetRegisters(Vue)就是负责挂载Vue.component/Vue.directive/Vue.filter三个注册方法的函数定义在 vue/src/core/global-api/assets.jsexport function initAssetRegisters (Vue: GlobalAPI) { /** * Create asset registration methods. */ 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)) { 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将注册方法依次挂载到 Vue 上。ASSET_TYPES定义在 vue/src/shared/constants.jsexport const ASSET_TYPES [ component, directive, filter ]所以实际上 Vue 初始化了3 个全局函数Vue.component、Vue.directive、Vue.filter它们的注册逻辑共用同一份模板代码。全局注册的完整处理流程以Vue.component(my-component, options)为例这段代码做了 4 件事校验组件名非生产环境下若type component先执行validateComponentName(id)。该校验逻辑在 vue/src/core/util/options.js 中要求组件名以字母开头、只能包含字母数字与连字符且不能与内置标签slot、component或平台保留标签冲突。对象转构造函数若type component且definition是纯对象isPlainObject则先补全definition.name definition.name || id再通过this.options._base.extend(definition)将普通对象转换为继承自 Vue 的构造函数。options._base在initGlobalAPI中被初始化为Vue自身vue/src/core/global-api/index.js 中的Vue.options._base Vue因此这里等价于调用Vue.extend。指令函数的特殊处理若type directive且definition是函数则自动包装为{ bind: definition, update: definition }这也是指令可以简写为单个函数的原因。挂载到 options最终执行this.options[type s][id] definition即把组件构造函数挂到Vue.options.components上并返回definition。另外值得注意的是当第二个参数definition缺省时Vue.component(id)会直接返回已注册的组件this.options[type s][id]因此Vue.component同时充当了「注册器」与「查询器」双重角色。组件构造函数的产生Vue.extend与 options 合并Vue.extend定义在 vue/src/core/global-api/extend.js 中它基于「原型式继承」为每个组件生成独立构造函数Sub其中有一段关键逻辑Sub.options mergeOptions( Super.options, extendOptions )也就是说每个子组件的options都会把Vue.options包含全局注册的components合并进来。mergeOptions的核心实现在 vue/src/core/util/options.js它对components这类资源选项使用的是mergeAssets策略function mergeAssets ( parentVal: ?Object, childVal: ?Object, vm?: Component, key: string ): Object { const res Object.create(parentVal || null) if (childVal) { process.env.NODE_ENV ! production assertObjectType(key, childVal, vm) return extend(res, childVal) } else { return res } }注意Object.create(parentVal)这一行——合并结果以父级Vue.options.components为原型局部注册的组件作为自身属性叠加在其上。这意味着任何组件实例访问components时都能通过原型链找到全局注册的组件这正是「全局组件到处可用」的底层保障。此外Vue.extend中还有一段用于支持递归组件的逻辑// enable recursive self-lookup if (name) { Sub.options.components[name] Sub }当组件提供了name选项时Sub会把自身注册进自己的components从而支持组件在模板中递归自引用——这也解释了报错信息里为什么强调递归组件要提供name选项。内置组件的全局预注册initGlobalAPI在初始化Vue.options时还会预置内置组件Vue.options Object.create(null) ASSET_TYPES.forEach(type { Vue.options[type s] Object.create(null) }) Vue.options._base Vue extend(Vue.options.components, builtInComponents)builtInComponents来自 vue/src/core/components/index.js目前只包含KeepAlive即keep-alive组件。而transition、transition-group等组件则是在 web 平台运行时目录vue/src/platforms/web/runtime/components/index.js中通过Vue.component注册的。这也解释了为何这些内置组件无需用户手动注册即可使用。渲染时的组件解析resolveAsset组件注册只是「存」真正「取」发生在渲染阶段创建 vnode 时。组件渲染函数最终会执行_createElement其定义在 vue/src/core/vdom/create-element.jsif (typeof tag string) { let Ctor ns (context.$vnode context.$vnode.ns) || config.getTagNamespace(tag) if (config.isReservedTag(tag)) { // platform built-in elements vnode new VNode( config.parsePlatformTagName(tag), data, children, undefined, undefined, context ) } else if (isDef(Ctor resolveAsset(context.$options, components, tag))) { // component vnode createComponent(Ctor, data, context, children, tag) } else { // unknown or unlisted namespaced elements vnode new VNode( tag, data, children, undefined, undefined, context ) } }解析顺序是config.isReservedTag(tag)若为平台保留标签HTML 原生元素直接创建普通元素 vnoderesolveAsset(context.$options, components, tag)从当前实例的vm.$options.components中解析组件解析成功则走createComponent创建组件 vnode否则按「未知元素」处理这也是文章开头那条Unknown custom element警告的由来。resolveAsset的实现同样在 vue/src/core/util/options.jsexport function resolveAsset ( options: Object, type: string, id: string, warnMissing?: boolean ): any { /* istanbul ignore if */ if (typeof id ! string) { return } const assets options[type] // check local registration variations first if (hasOwn(assets, id)) return assets[id] const camelizedId camelize(id) if (hasOwn(assets, camelizedId)) return assets[camelizedId] const PascalCaseId capitalize(camelizedId) 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 }解析逻辑依次尝试三种命名形态直接用原始id如模板中的my-component查找将id驼峰化camelize如myComponent后查找在驼峰化基础上首字母大写capitalize如MyComponent后查找最后再通过原型链兜底assets[id] || assets[camelizedId] || assets[PascalCaseId]。camelize与capitalize的实现位于 vue/src/shared/util.js前者用/-(\w)/g正则把连字符后字母转为大写后者用cached缓存纯函数结果。这就解释了为什么全局注册的组件 id 可以同时以**连字符kebab-case、驼峰camelCase或首字母大写PascalCase**三种形式在模板中使用。同时hasOwn自身属性判断 原型链兜底的组合也保证了局部注册优先于全局注册的查找顺序。局部注册components选项Vue.js 同样支持局部注册在组件内部使用components选项import HelloWorld from ./components/HelloWorld export default { components: { HelloWorld } }理解了全局注册的过程后局部注册就非常简单了——它本质上是一条更短的链路在组件实例化阶段Vue.prototype._initvue/src/core/instance/init.js会执行mergeOptions(resolveConstructorOptions(vm.constructor), options || {}, vm)将构造函数的options与实例选项合并其中components走mergeAssets策略以父级components含全局组件通过原型链可达为原型把局部注册的components作为自身属性叠加渲染阶段_createElement执行resolveAsset(context.$options, components, tag)时先命中自身属性局部组件再通过原型链命中全局组件。因此局部注册与全局注册在解析入口完全相同都是resolveAsset区别只在于组件构造函数被「存」在了哪里对比维度全局注册Vue.component局部注册components选项存放位置Vue.options.components所有组件的公共祖先当前组件构造函数的options.components生效范围所有组件实例经mergeOptions原型链逐层继承仅当前组件及其模板作用域定义时机全局 API 初始化阶段注册组件options合并阶段是否要求Vue.extend转换注册时自动通过_base.extend转换合并进options渲染解析时使用测试用例佐证仓库的单元测试对上述行为有直接验证。在 vue/test/unit/features/global-api/assets.spec.js 中should register a component用例验证了Vue.component(foo, { template: spanfoo/span })后实例模板中可直接使用foo与barlocal registration should take priority regardless of naming convention对应 issue #4434验证了局部注册优先于全局注册即便全局注册了x-foo只要组件内局部注册了同名的其他组件渲染时也会优先使用局部版本——这正是resolveAsset中hasOwn(assets, id)自身属性优先命中带来的行为。总结两种注册方式的本质差异与选型指导通过本文的源码分析可以得出以下核心结论注册的本质是「存放位置」的差异全局注册把组件构造函数存进Vue.options.components局部注册存进当前组件构造函数的options.components全局组件「处处可用」的根源是原型链mergeAssets用Object.create(parentVal)构造合并结果使每个组件实例的$options.components都能沿原型链访问到全局组件解析的唯一入口是resolveAsset渲染时_createElement通过resolveAsset(context.$options, components, tag)统一解析且依次尝试 kebab-case、camelCase、PascalCase 三种命名再以「自身属性优先、原型链兜底」的规则命中目标递归组件需要name选项Vue.extend在组件提供name时会将Sub注册进自身的components实现递归自引用。在实际工程中这一原理有非常直接的指导意义通用的基础组件按钮、输入框、弹窗等适合全局注册省去每个业务组件重复引入的成本而特例化的业务组件适合局部注册既能避免全局命名空间被大量无关组件污染也能通过「局部优先」的解析规则获得更可控的作用域行为。理解了背后的源码机制面对「该用全局注册还是局部注册」的问题时就不再是凭经验拍脑袋而是有据可依的工程决策。赞分享文档教程前端【免费下载链接】vue-analysis:thumbsup: Vue.js 源码分析项目地址https://gitcode.com/gh_mirrors/vu/vue-analysis点击查看免费下载相关推荐ugit vs 原生Git命令谁才是撤销操作的终极解决方案ugit vs 原生Git命令谁才是撤销操作的终极解决方案 在日常开发中我们经常会遇到执行错误的Git命令后急需撤销的情况。ugit也称为git undCelery 任务注册表TaskRegistry深度解析注册、反注册与任务查找机制Celery 任务注册表TaskRegistry深度解析注册、反注册与任务查找机制 celery.app.registry 是 Celery 分布式任务队任务调度后端消息队列上一篇2025嵌入式开发从驱动开发到系统优化的实战蜕变下一篇在Mac上将任何窗口强制置顶Topit让多任务管理变得如此简单创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
从结构体到对象:正式学习C++类的骨架、封装与this指针 文章目录1. C在C后的延伸2. 类的基本骨架:成员、类域和定义位置2. 类定义中放什么2.2 类内定义与类外定义2.3 class 和 struct 的差别3. 访问限定符:封装不是仅仅把数据藏起来3.1 public 和 private3.2 protected 先知晓边界即可4. 对象大小:… · 2026/9/27 9:39:21
皮带机巡检的四个必查点:跑偏、打滑、撕裂、托辊异响怎么判 一、跑偏:判定要看三处,不是看一眼
皮带机跑偏是最常见的故障,也是最容易被“凭感觉”处理的一项。真正可验收的判定要落在三个位置:头部滚筒、尾部滚筒、中部托辊组。行业通行口径是胶带中心线相对机架中心线的偏移量不超过带宽… · 2026/9/27 9:39:21
网站被黑挂马别慌!从零搭建个人网站视频建设全流程 网站被黑挂马别慌!从零搭建个人网站视频建设全流程 昨晚还在刷朋友圈,突然收到客户微信:“老张,我那个展示视频的官网打不开了,还跳出一堆乱七八糟的广告弹窗,是不是中病毒了?”这种场景在福建这边太常见了。很多做外贸或者本地服务的老板,手里有几个… · 2026/9/27 10:24:38
5个避坑指南教你photoshop网页版在线使用免费 5个避坑指南教你photoshop网页版在线使用免费 网站做好了没人访问?别急着加钱投广告,先查查你的站能不能被搜到。很多老板花几万块做个站,上线后天天盯着后台,流量个位数,心里慌得不行。其实问题往往出在细节上,比如图片没压缩、代码冗余、或… · 2026/9/27 10:24:32
南京招网站开发避坑指南:3个实战案例教你搞定域名备案 南京招网站开发避坑指南:3个实战案例教你搞定域名备案 网站上线了,后台数据一片空白,这是很多老板最头疼的事。在南京招网站开发,光看代码漂亮没用,得看流量能不能进得来。我见过太多南京的中小企业,花大价钱做了个响应式官网,结果因为DNS没配对、… · 2026/9/27 10:24:32
宁波seo外包3个坑:网站没人看?懂建站报价才不亏 宁波seo外包3个坑:网站没人看?懂建站报价才不亏 网站做好了没人访问,这不仅是焦虑,更是很多宁波企业主的真实痛点。我接过不少单子,发现大家往往把宝押在 建站报价… · 2026/9/27 10:24:32
简单的个人网站模板2026最新 个人网站模板避坑指南:3步搞定简单主页速查手册 想做网站却怕代码?别慌,这份简单的个人网站模板速查手册专治手残党。 你不需要懂后端,甚至不用装复杂的IDE,只要会复制粘贴,就能在半天内上线。… · 2026/9/27 10:24:26
Go Fx Value Groups 完整指南:多生产者多消费者场景下的批量依赖注入 后端开发工具 【免费下载链接】fx A dependency injection based application framework for Go. 项目地址: https://gitcode.com/gh_mirrors/fx1/fx 点击查看 免费下载 导读
本文围绕 Uber 开源的依赖注入框架 Fx(本仓库即其源码,模块导入… · 2026/9/27 10:24:26
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01