Vue實(shí)例創(chuàng)建和掛載的詳細(xì)過程
1. Vue 實(shí)例創(chuàng)建和掛載的過程概述
Vue 實(shí)例的掛載過程涉及多個關(guān)鍵步驟,包括創(chuàng)建實(shí)例、編譯模板、初始化數(shù)據(jù)和事件綁定等。它的核心流程大致如下:
- 初始化 Vue 實(shí)例:在
new Vue()
調(diào)用時,Vue 實(shí)例會創(chuàng)建并初始化相關(guān)的屬性,如data
、computed
、methods
等。 - 初始化生命周期:Vue 會初始化生命周期鉤子,包括
beforeCreate
、created
、beforeMount
、mounted
等。 - 編譯模板:Vue 會解析傳入的模板,生成虛擬 DOM(VNode)。
- 渲染:將虛擬 DOM 轉(zhuǎn)換為真實(shí)的 DOM,最終將 Vue 實(shí)例掛載到指定的 DOM 節(jié)點(diǎn)上。
- 更新:在響應(yīng)式數(shù)據(jù)變化時,Vue 會觸發(fā)更新,重新渲染組件。
2. 分析源碼:Vue 實(shí)例的創(chuàng)建與掛載過程
我們從 Vue 2.x 的源碼分析 Vue 實(shí)例的掛載過程。以下是大致的分析步驟。
2.1 Vue 實(shí)例的構(gòu)建函數(shù)
首先,我們來看 Vue 的構(gòu)建函數(shù),它通常是通過 new Vue(options)
來實(shí)例化 Vue 對象的。options
對象包含了組件的配置項(xiàng),比如 el
、data
、template
等。
function Vue(options) { if (process.env.NODE_ENV !== 'production' && !(this instanceof Vue)) { warn('Vue is a constructor and should be called with the `new` keyword'); } this._init(options); }
在構(gòu)造函數(shù)中,調(diào)用了 this._init(options)
,也就是實(shí)例化時 Vue 會調(diào)用內(nèi)部的 _init
方法進(jìn)行初始化。
2.2 Vue 的 _init 方法
Vue.prototype._init = function (options) { const vm = this; vm._uid = uid$1++; // 生成唯一 ID vm._isVue = true; // 標(biāo)記 Vue 實(shí)例 vm.$options = mergeOptions( resolveConstructorOptions(vm.constructor), options || {} ); // 合并構(gòu)造函數(shù)默認(rèn)選項(xiàng)和用戶傳入的選項(xiàng) vm._renderProxy = vm; // 渲染代理 vm._self = vm; // 指向自己 initLifecycle(vm); // 初始化生命周期 initEvents(vm); // 初始化事件 initRender(vm); // 初始化渲染 callHook(vm, 'beforeCreate'); // 調(diào)用生命周期鉤子 beforeCreate initState(vm); // 初始化數(shù)據(jù)、計算屬性等 initInjections(vm); // 處理依賴注入 callHook(vm, 'created'); // 調(diào)用生命周期鉤子 created if (vm.$options.el) { vm.$mount(vm.$options.el); // 掛載實(shí)例 } };
- 生命周期的初始化:在
_init
方法中,Vue 會進(jìn)行生命周期的初始化,并調(diào)用beforeCreate
和created
鉤子。 - 渲染代理:
_renderProxy
用于實(shí)現(xiàn)模板訪問this
時的代理。 $mount
:如果傳入了el
選項(xiàng),Vue 會調(diào)用$mount
方法來掛載實(shí)例。
2.3 Vue 的 $mount 方法
掛載的核心方法是 $mount
,它接受一個 DOM 元素或選擇器字符串,并將 Vue 實(shí)例與這個 DOM 節(jié)點(diǎn)進(jìn)行綁定。
Vue.prototype.$mount = function (el, hydrating) { el = el && query(el); // 如果傳入了 el,進(jìn)行選擇并獲取 DOM 元素 if (el === document.body || el === document.documentElement) { warn('Do not mount Vue to <html> or <body> - mount to normal elements instead.'); return; } const options = this.$options; if (!options.render) { let template = options.template; if (template) { if (typeof template === 'string') { // 編譯模板 template = compileToFunctions(template, this); } } else if (el) { // 沒有模板時,從 DOM 中獲取內(nèi)容作為模板 template = el.outerHTML; } options.render = template ? compileToFunctions(template, this) : createEmptyVNode; } return mountComponent(this, el, hydrating); };
- DOM 查詢:首先,
el
被解析成 DOM 元素。 - 模板編譯:如果沒有傳入渲染函數(shù) (
render
),Vue 會嘗試從模板字符串中編譯生成渲染函數(shù)。 mountComponent
:最后,調(diào)用mountComponent
來進(jìn)行組件的掛載。
2.4 mountComponent 方法
mountComponent
是掛載組件的核心方法,它會調(diào)用 vm.$el
將實(shí)例掛載到指定的 DOM 上。
function mountComponent(vm, el, hydrating) { vm.$el = el; callHook(vm, 'beforeMount'); let updateComponent; // 這里通過 render 函數(shù)來渲染視圖 updateComponent = function () { vm._update(vm._render(), hydrating); }; // 調(diào)用 Vue 的渲染函數(shù),執(zhí)行視圖更新 new Watcher(vm, updateComponent, noop, { before: callHook.bind(vm, 'beforeUpdate') }, true); callHook(vm, 'mounted'); return vm; }
- 調(diào)用
beforeMount
:在渲染之前,會先執(zhí)行beforeMount
生命周期鉤子。 - 渲染和更新:
updateComponent
會觸發(fā)vm._update
方法進(jìn)行視圖更新。_render()
是用于生成虛擬 DOM 的方法,它會調(diào)用渲染函數(shù)。 - Watcher:Vue 通過
Watcher
來觀察響應(yīng)式數(shù)據(jù)的變化,并在數(shù)據(jù)變化時觸發(fā)更新。
2.5 Vue 的 _update 方法
_update
方法會根據(jù)虛擬 DOM 的變化,重新渲染并更新 DOM。
Vue.prototype._update = function (vnode, hydrating) { const vm = this; const prevEl = vm.$el; const prevVnode = vm._vnode; vm._vnode = vnode; if (!prevVnode) { // 初次渲染 vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */); } else { // 更新渲染 vm.$el = vm.__patch__(prevVnode, vnode); } // 更新生命周期鉤子 callHook(vm, 'updated'); };
- 虛擬 DOM 比對:
_update
會執(zhí)行虛擬 DOM 與真實(shí) DOM 的比對,更新頁面內(nèi)容。 - 生命周期鉤子:更新后,會調(diào)用
updated
生命周期鉤子。
3. 總結(jié) Vue 實(shí)例掛載的過程
Vue 實(shí)例的掛載過程包含以下幾個主要步驟:
- 初始化實(shí)例:通過
new Vue(options)
創(chuàng)建 Vue 實(shí)例,調(diào)用_init
方法進(jìn)行初始化。 - 編譯模板:如果沒有傳入
render
函數(shù),Vue 會通過模板字符串生成渲染函數(shù)。 - 掛載組件:通過
$mount
方法將 Vue 實(shí)例掛載到指定的 DOM 元素上。 - 渲染更新:通過
_update
方法更新 DOM,生成新的視圖。 - 生命周期鉤子:在每個階段會觸發(fā)相應(yīng)的生命周期鉤子函數(shù)(如
beforeCreate
、created
、beforeMount
、mounted
等)。
通過以上分析,我們可以理解 Vue 實(shí)例掛載的完整過程,以及其中涉及的關(guān)鍵函數(shù)和生命周期鉤子。
到此這篇關(guān)于Vue實(shí)例創(chuàng)建和掛載的詳細(xì)過程的文章就介紹到這了,更多相關(guān)Vue實(shí)例創(chuàng)建和掛載內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
一步步教你利用webpack如何搭一個vue腳手架(超詳細(xì)講解和注釋)
這篇文章主要給大家介紹了軟玉利用webpack如何搭一個vue腳手架的相關(guān)資料,文中有超詳細(xì)講解和注釋,對大家學(xué)習(xí)或者使用webpack具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2018-01-01Vue+Echarts實(shí)現(xiàn)基本K線圖的繪制
這篇文章主要為大家詳細(xì)介紹了如何利用Vue和Echarts實(shí)現(xiàn)基本K線圖的繪制,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-03-03淺談Vue.js 1.x 和 2.x 實(shí)例的生命周期
下面小編就為大家?guī)硪黄獪\談Vue.js 1.x 和 2.x 實(shí)例的生命周期。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-07-07關(guān)于IDEA中的.VUE文件報錯 Export declarations are not supported by cu
這篇文章主要介紹了關(guān)于IDEA中的.VUE文件報錯 Export declarations are not supported by current JavaScript version的問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-10-10vue3在單個組件中實(shí)現(xiàn)類似mixin的事件調(diào)用
這篇文章主要為大家詳細(xì)介紹了vue3如何在單個組件中實(shí)現(xiàn)類似mixin的事件調(diào)用,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-01-01Vue3響應(yīng)式對象數(shù)組不能實(shí)時DOM更新問題解決辦法
在寫大文件上傳時,碰到關(guān)于 vue2 跟 vue3 對在循環(huán)中使用異步,并動態(tài)把普通對象添加進(jìn)響應(yīng)式數(shù)據(jù),在異步前后修改該普通對象的某個屬性,導(dǎo)致 vue2 跟 vue3 的視圖更新不一致,引發(fā)一系列的思考,所以本文介紹了Vue3響應(yīng)式對象數(shù)組不能實(shí)時DOM更新問題解決辦法2024-07-07