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、watch
callHook(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.js | created、mounted 等钩子 |
渲染函数 | src/core/instance/render.js | vm._render() |
虚拟 DOM → DOM | src/core/vdom/patch.js | diff 算法 |
响应式系统 | src/core/observer/ | 包含 Dep、Watcher、Observer |