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.js | created、mounted 等鉤子 |
渲染函數 | src/core/instance/render.js | vm._render() |
虛擬 DOM → DOM | src/core/vdom/patch.js | diff 算法 |
響應式系統 | src/core/observer/ | 包含 Dep、Watcher、Observer |