当前位置: 首页 > article >正文

Vue中的 VueComponent

VueComponent

组件的本质

  • Vue 组件是一个可复用的 Vue 实例。
  • 每个组件本质上就是通过 Vue.extend() 创建的构造函数,或者在 Vue 3 中是由函数式 API(Composition API)创建的。
// Vue 2
const MyComponent = Vue.extend({template: '<div>Hello</div>'
});

组件注册

  • 全局注册:Vue.component(‘MyComponent’, {…})
  • 局部注册:
export default {components: {MyComponent}
}

Props 和事件

  • props:父传子,用于组件参数传递。
  • 自定义事件 $emit:子传父。
// 子组件
this.$emit('update:value', newValue);

插槽 Slot

  • 默认插槽、具名插槽、作用域插槽。
<slot name="header"></slot>

生命周期钩子

  • beforeCreate → created → beforeMount → mounted → beforeUpdate → updated → beforeDestroy → destroyed

深入理解 VueComponent

VueComponent 的创建过程(以 Vue 2 为例)

Vue 执行 new Vue({…}) 时会走如下过程:

a. Vue.extend() 创建组件构造器

function VueComponent (options) {
this._init(options);
}

b. _init() 方法中合并配置、初始化生命周期、事件、render、data 等。

c. 渲染和挂载:调用 vm.$mount() → 创建 VNode → patch → 转换为真实 DOM。

组件更新机制

  • 响应式依赖收集(Dep 和 Watcher)
  • 数据变动触发组件局部更新(通过虚拟 DOM 的 diff 算法)。

🧩 VueComponent 源码解读(以 Vue 2.x 为主)

我们从组件创建 → 渲染 → 响应更新 → 销毁 全流程解读。

组件的创建过程

🔧 Vue.component() 注册组件

Vue.component('MyComp', {props: ['msg'],template: '<div>{{ msg }}</div>'
});

注册后,内部通过 Vue.options.components[‘MyComp’] 存储组件定义,等待使用。

注册本质:调用 extend 创建一个组件构造器(子类):

function initGlobalAPI (Vue) {Vue.component = function (id, definition) {if (typeof definition === 'object') {definition = Vue.extend(definition); // 核心!}Vue.options.components[id] = definition;}
}

🏗️ Vue.extend 组件构造器

源码位置:src/core/global-api/extend.js

Vue.extend = function (extendOptions) {const Sub = function VueComponent(options) {this._init(options);};Sub.prototype = Object.create(Vue.prototype); // 原型继承Sub.prototype.constructor = Sub;Sub.options = mergeOptions(Vue.options, extendOptions);return Sub;
};

重点:

  • 每个组件都是 Vue 的子类。
  • 合并父 Vue 的选项和当前组件的选项。

组件实例的初始化

当我们在模板中写 ,Vue 解析 VNode 时会进入 createComponent() → createComponentInstanceForVnode() → new VNode.componentOptions.Ctor()。

🔄 调用 vm._init()

位置:src/core/instance/init.js

Vue.prototype._init = function (options) {vm.$options = mergeOptions(resolveConstructorOptions(vm.constructor), options);initLifecycle(vm);initEvents(vm);initRender(vm);callHook(vm, 'beforeCreate');initState(vm); // 初始化 props、methods、data、computed、watchcallHook(vm, 'created');if (vm.$options.el) {vm.$mount(vm.$options.el);}
}

组件的挂载与渲染

🔨 vm.$mount() → 编译模板 → 生成 render 函数

位置:src/platforms/web/entry-runtime-with-compiler.js

const mount = Vue.prototype.$mount;
Vue.prototype.$mount = function (el) {el = document.querySelector(el);if (!this.$options.render) {const template = this.$options.template;const render = compileToFunctions(template);this.$options.render = render;}return mount.call(this, el);
}

🧱 渲染流程:render() → vnode → patch()

位置:src/core/instance/lifecycle.js

vm._update(vm._render());

•	_render() 执行 render 函数,返回 vnode。
•	_update() 使用 patch 将 vnode 转为真实 DOM。

响应式更新机制

🔁 组件的响应式核心依赖于:Observer、Dep、Watcher

  • data 中的数据会被劫持(defineReactive)
  • 每个组件对应一个渲染 watcher。
  • 数据更新时通知 Dep → 触发 watcher → 重新执行 render → 生成新 vnode → diff patch。
new Watcher(vm, updateComponent, noop);

组件销毁过程

调用 $destroy():

Vue.prototype.$destroy = function () {callHook(vm, 'beforeDestroy');// 删除 watcher// 解绑事件// 从 DOM 移除callHook(vm, 'destroyed');
}

🧬 源码主线流程总结(Vue 2)

Vue.component(…) → Vue.extend(…) → 组件构造函数 Sub

渲染 →
createComponent() →
new Sub(options) →
_init() →
mergeOptions → initState →
created → $mount()

$mount() →
compile(template) → render →
render() → vnode →
patch(vnode) → 挂载 DOM

数据更新 → Observer 触发 Dep.notify →
Watcher.update() → 重新 render → patch → 更新 DOM

📘 推荐文件入口

功能文件描述
全局 API 初始化src/core/global-api/index.js包括 Vue.component
组件构造器src/core/global-api/extend.js实现 Vue.extend
Vue 初始化src/core/instance/init.js实现 _init()
生命周期src/core/instance/lifecycle.jscreated、mounted 等钩子
渲染函数src/core/instance/render.jsvm._render()
虚拟 DOM → DOMsrc/core/vdom/patch.jsdiff 算法
响应式系统src/core/observer/包含 Dep、Watcher、Observer
http://www.lryc.cn/news/2387874.html

相关文章:

  • C语言数据结构-单向链表
  • 小样本分类新突破:QPT技术详解
  • Excel常用公式全解析(1):从基础计算到高级应用
  • C++ STL 容器:List 深度解析与实践指南
  • 每天掌握一个Linux命令 - ab(Apache Benchmark)
  • 与 PyCharm 官方沟通解决开发环境问题记录(进展:官方已推出2个新的修复版本)
  • Python的分布式网络爬虫系统实现
  • Vue快速上手(业务、技术、报错)
  • taro + vue3 实现小程序sse长连接实时对话
  • 使用MATLAB求解微分方程:从基础到实践
  • 基于MATLAB的大规模MIMO信道仿真
  • 如何在 Windows 和 Mac 上擦拭和清洁希捷外置硬盘
  • Vue 3.0 中状态管理Vuex 与 Pinia 的区别
  • 第三届黄河流域网安技能挑战赛复现
  • python 生成复杂表格,自动分页等功能
  • 2025年高防IP与游戏盾深度对比:如何选择最佳防护方案?
  • 在 Vue + Vite 项目中,直接使用相对路径或绝对路径引用本地图片资源时,图片无法正确显示。
  • 判断手机屏幕上的横向滑动(左滑和右滑)
  • 用户有一个Django模型没有设置主键,现在需要设置主键。
  • 【文献阅读】EndoChat: Grounded Multimodal Large Language Model for Endoscopic Surgery
  • React JSX语法介绍(JS XML)(一种JS语法扩展,允许在JS代码中编写类似HTML的标记语言)Babel编译
  • 【R语言编程绘图-箱线图】
  • 【elasticsearch 7 或8 的安装及配置SSL 操作指引】
  • GitHub 趋势日报 (2025年05月23日)
  • MongoDB索引:原理、实践与优化指南
  • SQL实战之索引优化(单表、双表、三表、索引失效)
  • [7-1] ADC模数转换器 江协科技学习笔记(14个知识点)
  • SSM整合:Spring+SpringMVC+MyBatis完美融合实战指南
  • Spring Boot分页查询进阶:整合Spring Data REST实现高效数据导航
  • 阿里云 Serverless 助力海牙湾构建弹性、高效、智能的 AI 数字化平台