目錄
一、依賴注入
1、?依賴注入是什么?
?2、最基礎的使用
?3、為什么使用依賴注入?
4、 使用 Symbol 作注入名
?二、異步組件
1、什么是異步組件?
2、最基礎用法:defineAsyncComponent
?3、在模板中使用異步組件
4、配置加載狀態:加載提示 / 超時 / 錯誤處理
三、生命周期?
?1、生命周期的本質:組件從“出生”到“死亡”的過程
2、生命周期鉤子總覽
3、 各生命周期鉤子的詳細解釋
1. setup()
2. onBeforeMount()
3. onMounted()
4. onBeforeUpdate()
5.onUpdated()
6. onBeforeUnmount()
7. onUnmounted()
4、鉤子參數?
?四、組合式函數
1、什么是組合式函數?
2、組合式函數的結構
3、組合式函數的核心特征
?4、組合式函數能做什么?
5、實戰場景匯總
6、總結一句話
?五、插件
1、什么是 Vue 插件?
2、插件的核心格式
?3、注冊方式
4、插件內部能做的事(功能總結)
5、注意事項
6、總結一句話
一、依賴注入
通常情況下,當我們需要從父組件向子組件傳遞數據時,會使用?props。想象一下這樣的結構:有一些多層級嵌套的組件,形成了一棵巨大的組件樹,而某個深層的子組件需要一個較遠的祖先組件中的部分數據。在這種情況下,如果僅使用 props 則必須將其沿著組件鏈逐級傳遞下去,這會非常麻煩:
1、?依賴注入是什么?
依賴注入是一種讓“祖先組件提供”和“后代組件注入使用”的機制,使用
provide
和inject
配合實現。
-
provide(key, value)
:祖先組件中聲明可供后代使用的內容 -
inject(key)
:后代組件中聲明需要注入的內容
?2、最基礎的使用
父組件(祖先)使用 provide
<script setup>
import { provide } from 'vue'
provide('color', 'blue')
</script>子組件(任意后代)使用 inject
<script setup>
import { inject } from 'vue'const color = inject('color')
</script>
<template><p style="color: {{ color }}">我是注入的顏色</p>
</template>
? 這樣,子組件就無需 props,可以跨越多層組件拿到祖先組件提供的數據。
如果提供的值是一個 ref,注入進來的會是該 ref 對象,而不會自動解包為其內部的值。這使得注入方組件能夠通過 ref 對象保持了和供給方的響應性鏈接。?
?3、為什么使用依賴注入?
傳統方式 | 問題 |
---|---|
使用 props | 需要每層組件手動傳遞,維護困難 |
使用 Vuex / pinia | 重,但適合全局狀態 |
使用 event bus | 不推薦,易維護混亂 |
? 依賴注入適合:
-
狀態共享(如配置、主題、權限)
-
插件式封裝(如表單、組件注冊)
-
面向組合邏輯的解耦
默認值與類型檢查
如果子組件注入的 key 不存在,返回值為 undefined
,你可以設置默認值:
const theme = inject('theme', 'light') // 默認值 fallback
你還可以傳入工廠函數作為默認值:
const config = inject('config', () => ({ color: 'blue' }))
4、 使用 Symbol 作注入名
但如果你正在構建大型的應用,包含非常多的依賴提供,或者你正在編寫提供給其他開發者使用的組件庫,建議最好使用 Symbol 來作為注入名以避免潛在的沖突。?
// keys.js
export const myInjectionKey = Symbol()// 在供給方組件中
import { provide } from 'vue'
import { myInjectionKey } from './keys.js'
provide(myInjectionKey, { /* 要提供的數據 */
})// 注入方組件
import { inject } from 'vue'
import { myInjectionKey } from './keys.js'const injected = inject(myInjectionKey)
?二、異步組件
Vue 的 異步組件(Async Components) 是一種優化性能與用戶體驗的機制,它允許你在需要時按需加載某個組件,而不是在應用啟動時一次性加載全部組件。
異步組件在構建大型應用、提升首屏加載速度、實現懶加載等場景中非常重要,Vue 為此提供了專門的語法和加載配置。
1、什么是異步組件?
異步組件是指:組件不是立即加載的,而是在需要時才異步地被加載。
它的核心思想是:“用的時候才加載”,這對以下場景非常有用:
-
頁面拆分(如路由頁面)
-
大型組件庫懶加載
-
多個組件中只有部分在運行中用到
2、最基礎用法:defineAsyncComponent
Vue 提供了官方函數 defineAsyncComponent()
來創建異步組件。
?基本語法:
import { defineAsyncComponent } from 'vue'const AsyncComponent = defineAsyncComponent(() =>import('./MyHeavyComponent.vue')
)
這個組件會被延遲加載,只有在模板中首次渲染它時,Vue 才會觸發 import()
加載它對應的文件。
?3、在模板中使用異步組件
<template><div><AsyncComponent /></div>
</template><script setup>
import { defineAsyncComponent } from 'vue'const AsyncComponent = defineAsyncComponent(() =>import('./MyHeavyComponent.vue')
)
</script>
4、配置加載狀態:加載提示 / 超時 / 錯誤處理
defineAsyncComponent
還可以接受一個對象,配置異步加載的過程行為。
?
import { defineAsyncComponent } from 'vue'const AsyncComponent = defineAsyncComponent({loader: () => import('./MyHeavyComponent.vue'),// 加載時展示的組件loadingComponent: LoadingSpinner,// 出錯時展示的組件errorComponent: ErrorMessage,// 延遲多長時間顯示 loadingComponent(毫秒)delay: 200,// 加載超時時間(毫秒)timeout: 3000,// 出錯時重試機制onError(error, retry, fail, attempts) {if (attempts <= 3) {retry()} else {fail()}}
})
各配置解釋:
選項 | 功能 |
---|---|
loader | 必填。返回組件的異步加載 Promise(即 import() ) |
loadingComponent | 加載過程中顯示的 UI |
errorComponent | 加載失敗后顯示的 UI |
delay | 加載多少毫秒后才顯示 loading |
timeout | 超過此時間未加載完成視為失敗 |
onError | 異步加載失敗時自定義處理(可自動重試) |
注意:Vue Router 內部會自動處理 loading 狀態,不需要你手動 defineAsyncComponent
。
三、生命周期?
Vue 的生命周期(Lifecycle)指的是 Vue 組件從創建到銷毀過程中經歷的一系列階段性鉤子函數,你可以在這些鉤子中執行邏輯,如數據初始化、DOM 操作、網絡請求、清理等。
每個 Vue 組件實例在其創建過程中都會經歷一系列初始化步驟,例如設置數據監聽、編譯模板、掛載 DOM,直到被銷毀。Vue 提供了生命周期鉤子函數,讓我們有機會在不同階段插入代碼。
?1、生命周期的本質:組件從“出生”到“死亡”的過程
?整個過程大致如下:
創建階段 → 掛載階段 → 更新階段 → 銷毀階段?
2、生命周期鉤子總覽
階段 | 鉤子函數 | 作用 |
---|---|---|
創建前 | setup() | Vue 3 中唯一入口 |
掛載前 | onBeforeMount() | 組件尚未掛載,DOM 還未生成 |
掛載后 | onMounted() | 組件已掛載,DOM 可操作 |
更新前 | onBeforeUpdate() | 響應式數據變更,但 DOM 還未更新 |
更新后 | onUpdated() | DOM 更新完畢,可做響應處理 |
卸載前 | onBeforeUnmount() | 組件將被銷毀,做清理前工作 |
卸載后 | onUnmounted() | 已銷毀,清理資源、解綁事件等 |
3、 各生命周期鉤子的詳細解釋
1. setup()
階段:組件創建階段(最先執行)
調用時機:組件實例剛創建,data
、props
、methods
都還沒綁定到 this
上
作用:
-
是組合式 API 的入口;
-
用來聲明響應式數據、props、emit、watch、計算屬性等;
-
不能訪問
this
; -
返回的變量會暴露給模板使用。
2. onBeforeMount()
階段:掛載前
調用時機:組件即將掛載到 DOM(el
創建完畢但未插入 DOM)
作用:
-
此時模板已編譯,但 DOM 未掛載;
-
可以進行某些準備工作或日志記錄。
常見用途:
-
初始化數據日志;
-
注冊未依賴 DOM 的第三方邏輯。
從組件“出生到上場”來理解生命周期
你可以把組件想象成一個“舞臺演員”:
階段 | 比喻 | 生命周期鉤子 |
---|---|---|
寫好劇本 | 編譯模板等準備工作 | setup() |
穿好衣服化妝 | DOM 虛擬結構準備就緒 | onBeforeMount() ? |
走上舞臺 | 掛載 DOM,出現在頁面 | onMounted() |
所以 onBeforeMount()
就是演員 剛準備好,馬上就要上場 的那一刻。
?Vue 在內部的執行流程:
setup() → 編譯模板 → 創建虛擬 DOM →?
→ 🔹onBeforeMount() →
→ 渲染并插入真實 DOM →
→ 🔹onMounted()
?onBeforeMount 做了什么?
-
組件已經準備好數據(比如
props
、ref
); -
已經生成了虛擬 DOM(VNode);
-
但還沒有插入真實頁面中;
-
所以此時你不能直接操作 DOM 元素。
能干什么?
雖然還不能訪問 DOM,但可以:?
-
準備數據(如果依賴 DOM 可延遲);
-
進行日志埋點或調試;
-
記錄組件加載時間;
-
檢查組件狀態是否完整;
-
準備動畫過渡參數(比如進入動畫前的狀態)。
3. onMounted()
階段:掛載后
調用時機:首次 DOM 渲染完成,所有 DOM 元素可操作
作用:
-
執行需要訪問 DOM 的邏輯;
-
發起初始請求;
-
注冊事件監聽器;
-
引入第三方庫(如 ECharts、Swiper)。
常見用途:
-
頁面初始化請求;
-
DOM 操作(如獲取滾動容器、焦點);
-
動畫執行。
你可以把它理解為:
“我的組件已經出現在頁面上了,現在可以操作它的 DOM、做異步請求、初始化動畫、注冊事件等。”
可以用 onMounted()
做哪些事?
用途 | 說明 |
---|---|
? 操作 DOM | 可以安全地訪問 document.querySelector 或 ref 引用的元素 |
? 發起 API 請求 | 初始化組件數據,如加載表格數據、詳情數據等 |
? 注冊監聽器 | 注冊 scroll 、resize 、keyboard 等全局事件 |
? 使用第三方庫 | 比如掛載圖表(ECharts)、富文本編輯器(Quill)等 |
? 初始化動畫 | 初始化進入動畫或過渡效果 |
? 上報埋點 | 發送統計日志、埋點監控等 |
4. onBeforeUpdate()
階段:更新前
調用時機:響應式狀態變化,DOM 還未更新
作用:
-
可用于比較新舊狀態;
-
做一些緩存或臨時邏輯。
注意事項:
-
不建議操作 DOM;
-
不要進行異步邏輯處理。
onBeforeUpdate()
是 Vue 組件中的一個更新階段生命周期鉤子,它在 響應式數據發生變化、DOM 還沒有更新之前 被調用。
你可以把它理解為:
“組件數據變了,DOM 馬上要重新渲染了,現在是我插手干預的最后機會。”
onBeforeUpdate() 的作用
用途 | 說明 |
---|---|
? 獲取舊的 DOM 狀態 | DOM 還沒變,你可以訪問“變化前”的樣子 |
? 計算更新前的一些值 | 比如滾動高度、舊位置 |
? 清除舊狀態標記 | 如之前的樣式、數據緩存 |
? 不適合做異步請求 | 更新前階段不能引起新響應式更新(否則會遞歸) |
5.onUpdated()
階段:更新后
調用時機:響應式數據更新完成,DOM 也已更新
作用:
-
可以對新 DOM 做處理;
-
常用于監聽局部 DOM 變化后執行邏輯。
onUpdated()
是 Vue 組件在 響應式數據變更導致 DOM 更新完成后 自動調用的生命周期鉤子。
你可以理解為:
“Vue 已經把新數據同步到了頁面上,現在你可以看到更新后的 DOM,想操作它、獲取它的新狀態、觸發動畫等等——就靠
onUpdated()
。”
onUpdated() 能做什么?
能做的事 | 應用場景 |
---|---|
? 讀取更新后的 DOM 狀態 | 比如新的高度、內容、布局 |
? 執行過渡動畫、樣式變化 | 比如 fade-in、滾動動畫等 |
? 動態調整布局 | 比如等高布局、表格自適應列寬 |
? 與舊值對比 | 和 onBeforeUpdate() 配合使用 |
? 不推薦用來發請求 | 頁面每次更新都會觸發,可能頻繁調用 |
?和onBeforeUpdate區別
項目 | onBeforeUpdate() | onUpdated() |
---|---|---|
調用時機 | DOM 更新前 | DOM 更新后 |
訪問的是 | 舊 DOM | 新 DOM |
場景 | 緩存、準備、清理 | 更新后調整布局、動畫 |
能否操作新結構 | ? 不行 | ? 可以 |
理解類比:裝修房子
你可以把 Vue 更新比喻成“家裝翻新”:
-
onBeforeUpdate()
:工人剛拿到設計圖紙,準備改造,但還沒開始動工; -
onUpdated()
:已經把墻刷好、燈裝上、地板換了,可以檢查結果了。
6. onBeforeUnmount()
階段:卸載前
調用時機:組件即將從頁面上被卸載
作用:
-
做清理工作,如清除定時器、取消監聽器;
-
防止內存泄漏;
-
通知外部容器取消操作。
?onBeforeUnmount()
是 Vue 組件即將被銷毀前調用的生命周期鉤子。
你可以理解為:
“Vue 準備把這個組件從頁面中移除,我現在有一個機會做一些清理工作或資源釋放。”
適合用 onBeforeUnmount()
做哪些事?
用途 | 舉例 |
---|---|
? 清除定時器 | clearInterval() 、clearTimeout() |
? 取消網絡請求 | 調用 AbortController.abort() 或取消 token |
? 移除事件監聽器 | removeEventListener() |
? 停止動畫或任務 | 比如取消動畫幀 cancelAnimationFrame() |
? 通知父組件或全局狀態 | 通知組件退出、清除緩存等 |
7. onUnmounted()
階段:卸載后
調用時機:組件 DOM 被完全移除
作用:
-
徹底釋放資源;
-
日志記錄、事件通知等。
注意事項:
-
通常清理邏輯建議放在
onBeforeUnmount()
,onUnmounted()
比較少用。
?onUnmounted()
是 Vue 組件在 被銷毀之后 自動調用的生命周期鉤子。
你可以理解為:
“Vue 已經把這個組件從頁面中移除了,DOM 不再存在,響應式狀態也都釋放了。這是我最后一次處理事情的機會。”
onUnmounted()
的典型用途
用途 | 示例 |
---|---|
? 日志記錄 / 調試 | 組件銷毀后打 log |
? 通知外部狀態 | 如 Vuex、Pinia 中的狀態重置 |
? 執行異步銷毀操作 | 提交狀態到后端、更新埋點日志等 |
? 銷毀訂閱 / 解耦邏輯清理 | 比如 event bus 或 WebSocket 等注冊事件 |
和 onBeforeUnmount()
的區別
鉤子 | 時機 | 是否可以訪問 DOM? | 用途 |
---|---|---|---|
onBeforeUnmount() | 銷毀前 | ? 是 | 清除定時器/監聽器 |
onUnmounted() | 銷毀后 | ? 否 | 日志、通知、埋點、最后狀態更新 |
一個指令的定義對象可以提供幾種鉤子函數 (都是可選的):?
const myDirective = {// 在綁定元素的 attribute 前// 或事件監聽器應用前調用created(el, binding, vnode) {// 下面會介紹各個參數的細節},// 在元素被插入到 DOM 前調用beforeMount(el, binding, vnode) {},// 在綁定元素的父組件// 及他自己的所有子節點都掛載完成后調用mounted(el, binding, vnode) {},// 綁定元素的父組件更新前調用beforeUpdate(el, binding, vnode, prevVnode) {},// 在綁定元素的父組件// 及他自己的所有子節點都更新后調用updated(el, binding, vnode, prevVnode) {},// 綁定元素的父組件卸載前調用beforeUnmount(el, binding, vnode) {},// 綁定元素的父組件卸載后調用unmounted(el, binding, vnode) {}
}
4、鉤子參數?
指令的鉤子會傳遞以下幾種參數:
-
el
:指令綁定到的元素。這可以用于直接操作 DOM。 -
binding
:一個對象,包含以下屬性。value
:傳遞給指令的值。例如在?v-my-directive="1 + 1"
?中,值是?2
。oldValue
:之前的值,僅在?beforeUpdate
?和?updated
?中可用。無論值是否更改,它都可用。arg
:傳遞給指令的參數 (如果有的話)。例如在?v-my-directive:foo
?中,參數是?"foo"
。modifiers
:一個包含修飾符的對象 (如果有的話)。例如在?v-my-directive.foo.bar
?中,修飾符對象是?{ foo: true, bar: true }
。instance
:使用該指令的組件實例。dir
:指令的定義對象。
-
vnode
:代表綁定元素的底層 VNode。 -
prevVnode
:代表之前的渲染中指令所綁定元素的 VNode。僅在?beforeUpdate
?和?updated
?鉤子中可用。
?四、組合式函數
?Vue 3 中的組合式函數(Composables)是基于組合式 API 構建的一個邏輯復用機制,它允許你將組件的狀態邏輯抽離成可重用的函數,這種方式比 Vue 2 的 Mixin、HOC 更清晰、更靈活、更易維護。
1、什么是組合式函數?
組合式函數是一個以
useXxx()
命名的普通 JavaScript 函數,在其中使用 Vue 的組合式 API(如ref
,reactive
,watch
,computed
等),然后將這些邏輯封裝并返回供多個組件使用。
簡化理解就是:
“把多個組件中重復的響應式邏輯、狀態、偵聽器等代碼封裝成函數,復用它們。”
2、組合式函數的結構
一個組合式函數的基本結構如下:
// useCounter.js
import { ref } from 'vue'export function useCounter() {const count = ref(0)function increment() {count.value++}return {count,increment}
}
在組件中使用它:
<script setup>
import { useCounter } from './useCounter'const { count, increment } = useCounter()
</script><template><button @click="increment">點擊:{{ count }}</button>
</template>
3、組合式函數的核心特征
特征 | 描述 |
---|---|
? 可重用 | 不同組件可調用相同的邏輯函數 |
? 組合式 API 支持 | 內部可以使用任何 ref、reactive、watch、computed 等 |
? 與組件解耦 | 邏輯不再依賴組件上下文 |
? 類型推導友好 | TypeScript 支持極好 |
? 易測試 | 普通函數,易于單元測試 |
?4、組合式函數能做什么?
1. 封裝狀態邏輯export function useToggle(initial = false) {const state = ref(initial)const toggle = () => (state.value = !state.value)return { state, toggle }
}
2. 封裝異步請求邏輯export function useFetch(url) {const data = ref(null)const error = ref(null)fetch(url).then(res => res.json()).then(json => (data.value = json)).catch(err => (error.value = err))return { data, error }
}
3. 封裝監聽器邏輯export function useMouse() {const x = ref(0)const y = ref(0)function update(e) {x.value = e.pageXy.value = e.pageY}onMounted(() => window.addEventListener('mousemove', update))onBeforeUnmount(() => window.removeEventListener('mousemove', update))return { x, y }
}
5、實戰場景匯總
場景 | 封裝為組合式函數 |
---|---|
表單驗證 | useFormValidation() |
網絡請求 | useFetch() , useAxios() |
用戶狀態管理 | useUser() |
頁面權限控制 | usePermission() |
響應式緩存 | useLocalStorage() , useSessionStorage() |
主題/系統設置 | useTheme() , useSystemConfig() |
響應式計數器 | useCounter() |
6、總結一句話
組合式函數是 Vue 3 中最推薦的邏輯復用機制,它允許你把多個組件重復的狀態、偵聽器、生命周期邏輯提取為獨立函數,提高代碼復用性、可維護性和清晰度。
?五、插件
1、什么是 Vue 插件?
Vue 插件(Plugin)是一個可以通過
app.use()
方法注冊到 Vue 應用中的擴展模塊。
它通常用于:
-
向應用注入功能(如添加全局方法、指令、組件等)
-
對整個應用進行配置或初始化
-
集成第三方庫(如 Vue Router、Vuex、Pinia、Element Plus 等)
2、插件的核心格式
Vue 插件其實就是一個具有 install(app, options)
方法的對象或函數:
?插件的標準寫法(對象形式):
// MyPlugin.js
export default {install(app, options) {// 1. 添加全局方法app.config.globalProperties.$hello = () => {console.log('Hello from plugin!')}// 2. 注冊全局組件app.component('MyGlobalComp', {template: `<div>I am global</div>`})// 3. 添加全局指令app.directive('focus', {mounted(el) {el.focus()}})// 4. 注入 provide/inject 數據app.provide('pluginName', 'MyPlugin')}
}
?3、注冊方式
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import MyPlugin from './MyPlugin'const app = createApp(App)
app.use(MyPlugin, { customOption: true }) // 安裝插件
app.mount('#app')
4、插件內部能做的事(功能總結)
功能 | 用法 |
---|---|
注冊全局組件 | app.component('Xxx', Component) |
注冊全局指令 | app.directive('xxx', definition) |
添加全局屬性 | app.config.globalProperties.$xxx = fn |
使用 provide/inject 傳遞全局依賴 | app.provide('xxx', value) |
啟動外部庫或執行初始化 | 如初始化配置項、加載配置文件等 |
5、注意事項
注意點 | 說明 |
---|---|
插件必須使用 app.use() 安裝 | 否則不會執行其 install() 方法 |
不要濫用全局屬性 | app.config.globalProperties 會污染組件上下文 |
插件之間避免命名沖突 | 推薦用命名空間前綴(如 $myXxx ) |
插件應保持純函數和無副作用 | 避免影響應用的穩定性 |
6、總結一句話
Vue 插件是通過
app.use()
安裝的功能擴展模塊,適合封裝和共享全局邏輯,如注冊組件、添加方法、集成第三方庫等,是構建大型項目或封裝組件庫的重要機制。
?