Vue 3 渲染機制解密:從模板到頁面的魔法

Vue 3 渲染機制解密

  • 前言
  • Vue 3的響應性系統
      • 1. **Reactivity API:**
      • 2. **Proxy 對象:**
      • 3. **Getter 和 Setter:**
      • 4. **依賴追蹤:**
      • 5. **批量更新:**
      • 6. **異步更新:**
      • 7. **遞歸追蹤:**
      • 8. **刪除屬性:**
  • 虛擬DOM的角色
      • 1. **減少直接操作真實 DOM:**
      • 2. **高效的批量更新:**
      • 3. **跨平臺開發:**
      • 4. **提高開發體驗:**
      • 5. **具備優化空間:**
      • 6. **簡化復雜度:**
  • 模板編譯
      • 1. **詞法分析(Lexical Analysis):**
      • 2. **優化(Optimization):**
      • 3. **生成代碼(Code Generation):**
      • 4. **創建渲染函數:**
      • 5. **渲染和更新:**
  • 渲染函數與VNode
      • 1. **渲染函數的基本結構:**
      • 2. **創建 VNode:**
      • 3. **嵌套子節點:**
      • 4. **動態數據綁定:**
      • 5. **遞歸調用渲染函數:**
  • Diff算法
      • 1. **Diff 算法的基本思想:**
      • 2. **Key 的作用:**
      • 3. **Diff 算法的三個階段:**
      • 4. **Diff 算法的優化手段:**
      • 5. **Diff 算法的時間復雜度:**
  • 異步更新
      • 1. **nextTick 的基本原理:**
      • 2. **nextTick 的用法:**
      • 3. **nextTick 的應用場景:**
      • 4. **nextTick 的注意事項:**
      • 5. **示例:**
  • 生命周期鉤子
      • 1. **創建階段(Creation):**
      • 2. **掛載階段(Mounting):**
      • 3. **更新階段(Updating):**
      • 4. **卸載階段(Unmounting):**
      • 5. **錯誤處理階段:**
      • 6. **示例:**
  • 渲染過程中的優化策略
      • 1. **虛擬 DOM 的靜態提升(Static Hoisting):**
      • 2. **靜態節點提升(Static Node Hoisting):**
      • 3. **事件處理函數的緩存:**
      • 4. **事件的冒泡處理:**
      • 5. **動態屬性的提升:**
      • 6. **事件的合并處理:**
      • 7. **節點的緩存:**
      • 8. **合并相鄰文本節點:**
      • 9. **scoped slots 的優化:**
      • 10. **響應式數據的緩存:**
  • 動態組件與懶加載
      • 1. **動態組件:**
      • 2. **懶加載:**
        • a. **異步組件:**
        • b. **工廠函數:**
      • 3. **結合動態組件和懶加載:**
  • 實例
  • 結尾

前言

在我們的前端世界中,頁面的渲染是一個看似簡單卻底層復雜的過程。Vue 3的渲染機制正是通過一系列魔法的步驟,將你編寫的模板轉變為用戶所看到的頁面。在這篇文章中,我們將揭開Vue 3的渲染魔法,帶你走進虛擬DOM的奇妙世界。
在這里插入圖片描述

Vue 3的響應性系統

Vue 3 的響應性系統基于 Proxy 對象,相較于 Vue 2 使用的 Object.defineProperty,它提供了更好的性能和更多的特性。以下是 Vue 3 響應性系統的一些關鍵概念:

1. Reactivity API:

Vue 3 引入了新的 Reactivity API,包括 reactivereftoRefs 等函數,用于創建響應式數據。

  • reactive 將對象轉化為響應式對象。

    import { reactive } from 'vue';const state = reactive({count: 0,
    });
    
  • ref 將基本數據類型包裝為響應式對象。

    import { ref } from 'vue';const count = ref(0);
    
  • toRefs 將響應式對象轉化為普通對象,其中每個屬性都是 ref。

    import { reactive, toRefs } from 'vue';const state = reactive({count: 0,
    });const { count } = toRefs(state);
    

2. Proxy 對象:

Vue 3 使用 Proxy 對象來追蹤對象的變化。Proxy 允許攔截對象的操作,比如讀取、設置、刪除屬性等。這使得 Vue 3 可以更精確地追蹤數據的變化。

3. Getter 和 Setter:

當訪問響應式對象的屬性時,Vue 3 會通過 Proxy 的 getter 攔截器來追蹤這個屬性的依賴關系。當修改屬性時,Vue 3 會通過 setter 攔截器來觸發重新渲染。

4. 依賴追蹤:

Vue 3 使用了一種稱為“依賴追蹤”的機制,它會在組件渲染過程中追蹤響應式數據的依賴關系。當數據變化時,Vue 3 可以精確地知道哪些組件需要重新渲染。

5. 批量更新:

Vue 3 會對觸發 setter 操作的地方進行批量更新,以減少重復的渲染操作,提高性能。

6. 異步更新:

Vue 3 在更新響應式數據時采用異步更新的策略,這意味著數據變化后不會立即觸發重新渲染,而是等到整個事件循環結束后再進行一次更新。這有助于避免不必要的重復渲染。

7. 遞歸追蹤:

Vue 3 能夠遞歸地追蹤嵌套對象的變化,保證整個對象樹的響應性。

8. 刪除屬性:

當刪除對象的屬性時,Vue 3 也能夠追蹤到這個操作,從而觸發重新渲染。

這些概念構成了 Vue 3 的響應性系統,使得 Vue 3 在數據變化時能夠高效地追蹤依賴關系,并觸發相應的重新渲染。這一改進帶來了更好的性能和更精確的響應式數據追蹤。

虛擬DOM的角色

虛擬 DOM(Virtual DOM)是一種在內存中維護的抽象表示,用于描述真實 DOM 的結構。Vue 3 中依然使用虛擬 DOM,其主要作用是優化 DOM 操作的效率,提高渲染性能。以下是虛擬 DOM 在 Vue 3 中的角色和作用:

1. 減少直接操作真實 DOM:

直接操作真實 DOM 是一項昂貴的操作,因為每次更新都會導致瀏覽器的重排和重繪。虛擬 DOM 充當了一個緩沖區,組件的變化首先在虛擬 DOM 中進行,然后通過算法比對,最終只更新真實 DOM 中實際變化的部分。

2. 高效的批量更新:

虛擬 DOM 允許 Vue 3 在內存中進行高效的批量更新。組件的狀態變化會首先在虛擬 DOM 中反映出來,然后通過比對算法找到真實 DOM 中需要更新的部分。這樣 Vue 3 可以收集多個狀態變化,然后一次性更新真實 DOM,減少了重排和重繪的次數。

3. 跨平臺開發:

虛擬 DOM 的抽象特性使得 Vue 3 能夠更輕松地支持跨平臺開發,例如在瀏覽器中以及在 NativeScript 或 Weex 等平臺上運行。Vue 3 的渲染器(Renderer)可以根據目標平臺生成相應的真實 DOM 操作。

4. 提高開發體驗:

使用虛擬 DOM 可以提高開發體驗,因為它允許開發者在更新過程中更輕松地理解組件狀態的變化。開發者可以專注于描述期望的 UI 結構,而不必關心底層 DOM 操作的細節。

5. 具備優化空間:

虛擬 DOM 具備一定的優化空間,因為它可以根據具體的應用場景和算法來進行不同程度的優化。例如,Vue 3 可以通過合并多個更新操作,最小化 DOM 操作,以提高性能。

6. 簡化復雜度:

使用虛擬 DOM 可以簡化復雜度。由于虛擬 DOM 是組件狀態的抽象表示,它幫助 Vue 3 在多個層次上進行狀態的管理,使得組件更新的過程更加可控和可預測。

總的來說,虛擬 DOM 在 Vue 3 中的作用是通過在內存中維護一個抽象表示來優化 DOM 操作,提高渲染性能,并為跨平臺開發提供支持。它允許開發者更高效地更新組件狀態,提供了一層抽象,隱藏了底層 DOM 操作的復雜性。

模板編譯

Vue 3 的模板編譯過程是將模板轉化為渲染函數,這個過程包含了一系列的步驟,其中涉及到詞法分析、語法分析、優化和生成代碼等。以下是 Vue 3 模板編譯的基本流程:

1. 詞法分析(Lexical Analysis):

首先,Vue 3 會對模板進行詞法分析,將模板字符串轉化為一系列的詞法單元(tokens)。詞法分析的任務是將模板字符串拆分為一個個的詞法單元,每個詞法單元表示模板中的一個語法結構。

在詞法分析的基礎上,Vue 3 進行語法分析,構建抽象語法樹(Abstract Syntax Tree,AST)。AST 是一種樹狀的數據結構,表示了模板中各個語法結構之間的關系。語法分析的目的是理解模板的結構,為后續的優化和代碼生成提供基礎。

2. 優化(Optimization):

經過語法分析后,Vue 3 會對 AST 進行一些優化操作,例如靜態節點提升、靜態屬性提升等。這些優化步驟旨在減少運行時的開銷,提高渲染性能。Vue 3 在編譯階段就可以識別出那些在渲染過程中不會發生變化的部分,從而進行靜態提升。

3. 生成代碼(Code Generation):

經過優化的 AST 將被用于生成渲染函數。Vue 3 利用生成的渲染函數來動態地生成最終的渲染代碼。渲染函數負責根據組件的狀態(響應式數據)生成 Virtual DOM,并最終更新到真實 DOM。生成的代碼是一段 JavaScript 代碼,它包含了模板中的邏輯和渲染行為。

4. 創建渲染函數:

通過生成的渲染代碼,Vue 3 將其包裝成一個渲染函數。這個渲染函數接受組件實例的狀態作為參數,然后執行渲染邏輯,生成 Virtual DOM。

5. 渲染和更新:

生成的渲染函數將被用于初始化組件的渲染,以及在組件狀態變化時觸發的更新。渲染函數的執行結果是 Virtual DOM,Vue 3 會利用這個 Virtual DOM 進行比對(diff)和最終的 DOM 更新。

總的來說,Vue 3 的模板編譯過程是一個將模板轉化為渲染函數的復雜流程,它通過詞法分析、語法分析、優化和代碼生成等步驟,最終生成可以動態執行的渲染函數。這個渲染函數負責根據組件的狀態生成 Virtual DOM,并在狀態變化時更新真實 DOM,從而實現視圖的動態變化。

渲染函數與VNode

在 Vue 3 中,渲染函數的主要任務是根據組件的狀態(響應式數據)生成虛擬節點(VNode)樹。以下是 Vue 3 中渲染函數生成 VNode 樹的基本過程:

1. 渲染函數的基本結構:

Vue 3 的渲染函數是一個普通的 JavaScript 函數,接收一個參數,通常是上下文對象,包括組件的狀態、props、slots 等信息。渲染函數的基本結構如下:

function render() {// 渲染邏輯
}

2. 創建 VNode:

渲染函數的核心是創建虛擬節點(VNode)。VNode 是對真實 DOM 的抽象表示,它描述了節點的類型、屬性、子節點等信息。Vue 3 提供了 h 函數(createElement 的別名)來創建 VNode。

import { h } from 'vue';function render() {return h('div', { class: 'container' }, 'Hello, Vue 3!');
}

上述代碼中,h 函數接受三個參數:節點類型(字符串或組件)、屬性對象、子節點。這樣,h 函數將創建一個表示 <div class="container">Hello, Vue 3!</div> 的 VNode。

3. 嵌套子節點:

渲染函數可以嵌套調用 h 函數,以構建包含子節點的 VNode 樹。子節點可以是字符串、數組、其他 VNode 等。

import { h } from 'vue';function render() {return h('div', { class: 'container' }, [h('p', 'Paragraph 1'),h('p', 'Paragraph 2'),]);
}

上述代碼中,h 函數構建了一個包含兩個段落的 <div> 元素。

4. 動態數據綁定:

渲染函數中可以使用組件的狀態(響應式數據)來動態綁定數據。

import { h, reactive } from 'vue';function render() {const state = reactive({message: 'Hello, Vue 3!',});return h('div', { class: 'container' }, state.message);
}

在這個例子中,state.message 是一個響應式數據,當其發生變化時,渲染函數會自動更新生成的 VNode。

5. 遞歸調用渲染函數:

渲染函數可以遞歸調用自身,實現動態的 VNode 生成。

import { h } from 'vue';function renderList(items) {return h('ul', items.map(item => h('li', item)));
}function render() {const data = ['Item 1', 'Item 2', 'Item 3'];return renderList(data);
}

在這個例子中,renderList 函數遞歸調用 h 函數,生成了一個動態列表的 VNode。

總體而言,Vue 3 的渲染函數通過調用 h 函數來創建虛擬節點,這些虛擬節點組成了一個 VNode 樹。這個 VNode 樹在組件狀態變化時會被動態更新,最終用于實現視圖的動態渲染。這種虛擬節點的抽象使得 Vue 3 能夠更高效地處理組件的渲染和更新,減少了直接操作真實 DOM 的開銷。

Diff算法

Vue 3 中使用的 Virtual DOM Diff 算法,也稱為 “patch” 算法,是一種智能比較 Virtual DOM 的算法,旨在最小化對真實 DOM 的操作次數,提高渲染性能。以下是 Vue 3 中 Diff 算法的核心原理和一些優化手段:

1. Diff 算法的基本思想:

Diff 算法的基本思想是通過比較新舊 VNode 的結構,找出兩者之間的差異,然后只對差異部分進行更新。這樣可以避免對整個真實 DOM 進行不必要的操作,提高渲染效率。

2. Key 的作用:

Vue 3 中,每個 VNode 都可以附帶一個唯一的 key 值。Key 的作用是幫助 Diff 算法識別 VNode 的唯一性,從而在更新過程中更精確地定位差異。通過 key,Diff 算法能夠識別出新舊 VNode 中哪些節點是相同的,哪些是新增、刪除或需要更新的。

3. Diff 算法的三個階段:

Diff 算法可以分為三個階段:新舊 VNode 的比較、差異的打補丁、打補丁到真實 DOM

  • 比較階段: 對新舊 VNode 進行深度優先遍歷,比較節點類型、key、data 等,找出相同節點和需要更新的節點。

  • 打補丁階段: 將比較的結果應用到真實 DOM 上,只對差異部分進行更新,減少 DOM 操作。

  • 應用到真實 DOM 階段: 將差異應用到真實 DOM,這一步驟使用遞歸和迭代的方式,確保整個差異樹都被正確地應用到真實 DOM 中。

4. Diff 算法的優化手段:

Vue 3 的 Diff 算法通過一些優化手段,減少了比較的復雜度和提高了性能。

  • 相同節點的直接復用: 如果新舊 VNode 是相同的(類型相同、key 相同),則直接復用舊節點,不再深入比較子節點。

  • 靜態節點提升: 對于靜態節點,即不會發生變化的節點,Diff 算法會在比較時將其提升為常量,避免不必要的比較。

  • 節點的緩存: Diff 算法會緩存已經比較過的節點,減少重復比較的次數。

  • 文本節點的優化: 對于文本節點,Diff 算法會直接比較文本內容,避免不必要的 DOM 操作。

  • Key 的作用: 合理使用 key,有助于 Diff 算法的性能優化,提高節點比較的精確性。

5. Diff 算法的時間復雜度:

Vue 3 的 Diff 算法的時間復雜度是 O(n),其中 n 是節點的數量。這是因為 Diff 算法會通過 key 來標識相同節點,從而避免不必要的節點比較。

總體而言,Vue 3 的 Diff 算法通過對比新舊 VNode,找出它們之間的差異,并通過一系列的優化手段來減少 DOM 操作次數,提高了渲染性能。 Key 的合理使用和一些優化手段使得 Diff 算法在大多數情況下能夠高效地工作。

異步更新

在 Vue 3 中,通過 nextTick 方法實現異步更新,確保在數據變化后的下一刻進行渲染。nextTick 利用了 JavaScript 的事件循環機制,將回調函數推遲到下一個事件循環中執行。以下是 nextTick 的基本原理和用法:

1. nextTick 的基本原理:

nextTick 利用 JavaScript 的事件循環(Event Loop)機制,將回調函數推遲到下一個事件循環中執行。在 Vue 3 中,nextTick 被用于在數據發生變化后等待一輪事件循環,然后執行回調函數,以確保在更新數據后進行 DOM 渲染。

2. nextTick 的用法:

在 Vue 3 中,nextTick 是通過 Vue 實例的 $nextTick 方法提供的。你可以在組件內或全局使用 $nextTick

// 在組件內使用
export default {methods: {someMethod() {// 在數據變化后執行回調this.$nextTick(() => {// DOM 更新完成后的操作});},},
};
// 在全局使用
import { nextTick } from 'vue';nextTick(() => {// 在數據變化后執行回調// DOM 更新完成后的操作
});

3. nextTick 的應用場景:

  • 在更新數據后獲取更新后的 DOM: 當數據更新后,可能需要獲取更新后的 DOM 元素,例如在計算元素的尺寸或位置等。

  • 在數據變化后執行一些操作: 當數據變化后,需要執行一些操作,但希望在 DOM 更新完成后再執行,可以使用 nextTick

  • 在 Vue 生命周期鉤子中的異步操作: 在 Vue 生命周期鉤子中進行一些異步操作時,為了確保 DOM 已經更新,可以使用 nextTick

4. nextTick 的注意事項:

  • nextTick 不保證異步執行的順序: 多個 nextTick 回調的執行順序不一定是按照它們被調用的順序。

  • nextTick 不會等待整個事件循環結束: nextTick 只會等待當前事件循環內的所有操作完成,而不是整個事件循環。

5. 示例:

下面是一個簡單的示例,演示了如何使用 nextTick 在數據更新后獲取更新后的 DOM:

<template><div ref="myElement">{{ message }}</div>
</template><script>
export default {data() {return {message: 'Hello, Vue 3!',};},mounted() {this.message = 'Updated Message';// 使用 nextTick 在數據更新后獲取更新后的 DOMthis.$nextTick(() => {const updatedElement = this.$refs.myElement;console.log(updatedElement.innerText); // 輸出:Updated Message});},
};
</script>

在這個示例中,mounted 鉤子中更新了數據 message,然后使用 nextTick 在數據更新后獲取了更新后的 DOM 元素。

生命周期鉤子

Vue 3 的生命周期包括創建階段、更新階段和銷毀階段,每個階段都有相應的生命周期鉤子函數。以下是 Vue 3 中主要的生命周期鉤子函數,以及在不同階段發生了什么:

1. 創建階段(Creation):

  • beforeCreate: 在實例初始化之后,數據觀測和事件配置之前被調用。此時實例還未初始化,因此無法訪問數據和實例方法。

  • created: 在實例創建完成后被調用。此時實例已經完成了數據觀測、屬性和方法的運算,但是掛載階段還未開始。在這個階段,可以訪問數據、實例方法,但無法訪問 DOM。

2. 掛載階段(Mounting):

  • beforeMount: 在掛載開始之前被調用。在此時,模板編譯完成,但尚未將模板渲染成真實的 DOM。

  • mounted: 在掛載完成之后被調用。此時實例已經掛載到 DOM 上,可以訪問到模板渲染后的內容。這是執行初始渲染的理想位置。

3. 更新階段(Updating):

  • beforeUpdate: 在數據更新時調用,發生在虛擬 DOM 重新渲染和打補丁之前。在這個時候,DOM 尚未更新。

  • updated: 在數據更新之后被調用,發生在虛擬 DOM 重新渲染和打補丁之后。在這個階段,可以執行依賴于 DOM 的操作。

4. 卸載階段(Unmounting):

  • beforeUnmount: 在卸載開始之前被調用。在這個時候,實例仍然完全可用。

  • unmounted: 在卸載完成之后被調用。在這個時候,實例已經被銷毀,無法再訪問數據和方法。

5. 錯誤處理階段:

  • errorCaptured: 在子組件拋出錯誤時被調用。它會向上冒泡并在父組件中觸發 errorCaptured 鉤子。可以用于捕獲組件樹中任一組件的錯誤。

6. 示例:

以下是一個簡單的組件,展示了不同生命周期鉤子的執行順序:

<template><div>{{ message }}</div>
</template><script>
export default {data() {return {message: 'Hello, Vue 3!',};},beforeCreate() {console.log('beforeCreate: ' + this.message);},created() {console.log('created: ' + this.message);},beforeMount() {console.log('beforeMount: ' + this.message);},mounted() {console.log('mounted: ' + this.message);},beforeUpdate() {console.log('beforeUpdate: ' + this.message);},updated() {console.log('updated: ' + this.message);},beforeUnmount() {console.log('beforeUnmount: ' + this.message);},unmounted() {console.log('unmounted: ' + this.message);},
};
</script>

在控制臺中你可以看到生命周期鉤子函數的執行順序,以及每個階段發生的時機。這有助于理解 Vue 3 中組件生命周期的整個生命周期過程。

渲染過程中的優化策略

Vue 3 在渲染過程中采用了一系列的優化策略,以提高頁面的渲染性能。以下是一些常見的優化策略:

1. 虛擬 DOM 的靜態提升(Static Hoisting):

在編譯階段,Vue 3 會通過靜態分析,將那些不會改變的節點標記為靜態節點,并在渲染時直接使用常量,減少對這些節點的比較和渲染開銷。這一優化策略被稱為靜態提升,可以顯著減少 Virtual DOM 的創建和比較的工作量。

2. 靜態節點提升(Static Node Hoisting):

類似于靜態提升,靜態節點提升是通過標記和提升純靜態的子節點,將其放置在渲染函數之外,只計算一次,減少不必要的計算。

3. 事件處理函數的緩存:

Vue 3 會為事件處理函數生成緩存,以避免在每次渲染時都創建新的函數。這種緩存機制可以提高事件處理的效率,特別是在包含循環的場景中。

4. 事件的冒泡處理:

Vue 3 優化了事件的冒泡處理機制,通過合并相同類型的事件監聽器,減少了事件處理的開銷。

5. 動態屬性的提升:

Vue 3 在編譯階段會對動態綁定的屬性進行提升,將其作為局部變量存儲,避免重復計算和創建。

6. 事件的合并處理:

當存在相同的事件監聽器時,Vue 3 會合并它們,以減少渲染時的監聽器數量。這種合并機制有助于減少 DOM 操作的成本。

7. 節點的緩存:

Vue 3 使用緩存機制,避免重復創建相同類型的節點。當相同類型的節點需要被創建時,Vue 3 會直接復用之前的節點,減少創建和銷毀的開銷。

8. 合并相鄰文本節點:

Vue 3 在渲染時會盡量合并相鄰的文本節點,減少 DOM 操作的次數。

9. scoped slots 的優化:

Vue 3 在處理 scoped slots 時,采用了更高效的算法,以減少渲染時的性能開銷。

10. 響應式數據的緩存:

Vue 3 對響應式數據進行了緩存,避免重復計算,提高數據訪問的效率。

這些優化策略的引入使得 Vue 3 在渲染過程中更加高效,減少了不必要的計算和 DOM 操作,從而提高了頁面的渲染性能。當然,具體的優化效果還受到頁面結構、數據規模等因素的影響,因此在實際項目中,綜合考慮多個方面來進行性能優化是非常重要的。

動態組件與懶加載

在大型應用中,通過動態組件和懶加載可以有效優化渲染性能,減少初始加載時間。以下是如何使用動態組件和懶加載的方法:

1. 動態組件:

動態組件是指在運行時動態地選擇和渲染不同的組件。在 Vue 中,你可以使用 component 元素并通過 is 屬性來實現動態組件的切換。

<template><div><component :is="currentComponent"></component></div>
</template><script>
import ComponentA from './ComponentA.vue';
import ComponentB from './ComponentB.vue';export default {data() {return {currentComponent: 'ComponentA',};},methods: {switchComponent() {this.currentComponent = (this.currentComponent === 'ComponentA') ? 'ComponentB' : 'ComponentA';},},
};
</script>

在上面的例子中,<component :is="currentComponent"></component> 根據 currentComponent 的值動態渲染不同的組件。

2. 懶加載:

懶加載是指只在組件需要時再去加載對應的代碼和資源。在 Vue 中,你可以使用異步組件和工廠函數來實現懶加載。

a. 異步組件:
const AsyncComponent = () => import('./AsyncComponent.vue');export default {components: {AsyncComponent,},
};

在上述代碼中,import('./AsyncComponent.vue') 返回一個 Promise,Vue 在需要渲染這個組件時才會執行這個 Promise,加載對應的組件代碼。

b. 工廠函數:
const AsyncComponent = () => ({component: import('./AsyncComponent.vue'),loading: LoadingComponent,delay: 200, // 加載組件前的延遲時間timeout: 3000, // 加載超時時間
});export default {components: {AsyncComponent,},
};

工廠函數返回一個對象,其中的 component 是一個 Promise,其他字段用于配置加載過程中的顯示。

3. 結合動態組件和懶加載:

你可以將動態組件和懶加載結合起來,以實現在需要時才加載和渲染組件。

<template><div><component :is="currentComponent"></component><button @click="switchComponent">Switch Component</button></div>
</template><script>
export default {data() {return {currentComponent: null,};},methods: {switchComponent() {import('./DynamicComponent.vue').then(module => {this.currentComponent = module.default;});},},
};
</script>

在這個例子中,switchComponent 方法中使用 import 異步加載了 DynamicComponent.vue 組件,然后將其賦值給 currentComponent,從而實現了懶加載和動態組件的結合使用。

通過動態組件和懶加載的優化,你可以延遲加載大型應用中的部分組件,從而提升初始加載速度,降低首次渲染的時間成本。

實例

理論知識的應用通常會依賴于具體的項目場景和需求。下面我將演示一個實例,使用Vue 3的動態組件和懶加載來優化一個簡單的多頁面應用(Multi-Page Application,MPA)。

假設我們有一個多頁面應用,包含兩個頁面:首頁(Home)和關于頁(About)。我們希望在用戶訪問不同頁面時,才加載并渲染相應的組件,以提高初始加載速度。

首先,我們創建兩個頁面組件:

Home.vue:

<template><div><h1>Welcome to the Home Page!</h1><!-- Home Page Content --></div>
</template>

About.vue:

<template><div><h1>About Us</h1><!-- About Page Content --></div>
</template>

接下來,我們創建一個布局組件(Layout),用于容納不同頁面的內容。在這個布局組件中,我們使用動態組件和懶加載來實現按需加載:

Layout.vue:

<template><div><header><nav><router-link to="/">Home</router-link> |<router-link to="/about">About</router-link></nav></header><main><!-- 使用動態組件根據當前路由渲染不同頁面 --><component :is="currentRouteComponent"></component></main></div>
</template><script>
export default {data() {return {// 根據路由動態加載的組件currentRouteComponent: null,};},watch: {$route(to) {// 根據路由變化動態設置要加載的組件this.loadRouteComponent(to);},},created() {// 初始化時加載當前路由對應的組件this.loadRouteComponent(this.$route);},methods: {async loadRouteComponent(route) {// 根據路由異步加載對應的組件const componentName = route.name || 'Home';const componentModule = await import(`@/views/${componentName}.vue`);this.currentRouteComponent = componentModule.default;},},
};
</script>

在這個例子中,我們使用了 Vue Router 來處理頁面切換。Layout 組件中的動態組件通過 :is 屬性根據當前路由來動態渲染不同的頁面組件。通過 import 異步加載頁面組件,實現了懶加載的效果。

在項目中,你需要配置 Vue Router,并在入口文件中引入和使用它。這個例子主要演示了如何在一個多頁面應用中,通過動態組件和懶加載來優化渲染機制,實現頁面按需加載,提高初始加載速度。

結尾

通過本文,你將深入了解Vue 3渲染機制的方方面面,為你的Vue開發之路增添更多的技術深度。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/160884.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/160884.shtml
英文地址,請注明出處:http://en.pswp.cn/news/160884.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【java】想要限制每次查詢的結果集不能超過10000行,該如何實現?

文章目錄 前言 前言 對于一些Saas化軟件&#xff0c;當某個租戶在執行查詢SQL時&#xff0c;如果查詢條件出現了BUG&#xff0c;導致去查了所有租戶的數據&#xff0c;這種情況是非常嚴重的&#xff0c;此時就需要在架構層面做限制&#xff0c;禁止一些特殊SQL的執行&#xff…

@PropertySource適配通配符加載到Environment的一種方案

PropertySource可將配置文件加載到內存&#xff0c;時間有限說干的&#xff0c;PropertySource注解有4個參數&#xff0c;其中value表示要加載文件的路徑&#xff0c;這個參數不支持通配符。還有一個參數PropertySourceFactory是加載配置文件的工廠&#xff0c;這兩個參數配合使…

【GUI】-- 13 貪吃蛇小游戲之食物及成績判斷

GUI編程 04 貪吃蛇小游戲 4.4 第四步&#xff1a;食物及成績判斷 首先&#xff0c;添加食物與分數的數據定義&#xff1a; //食物的坐標int foodX;int foodY;Random random new Random();//積分面板數據結構int score;在初始化方法中&#xff0c;添加(畫出)食物與分數&…

CSDN最新最全pytest系列——pytest-base-url插件之配置可選的項目系統UR

前言 ①當我們的自動化代碼完成之后&#xff0c;通常期望可以在不同的環境進行測試&#xff0c;此時可以將項目系統的URL單獨拿出來&#xff0c;并且可以通過pytest.ini配置文件和支持pytest命令行方式執行。 ② pytest-base-url 是一個簡單的pytest插件&#xff0c;它通過命…

紐扣電池上架TEMU、亞馬遜美國站需要做什么認證?紐扣電池認證標準16CFR1700.15,16CFR1700.20

近日&#xff0c;Temu連發多條賣家彈窗內容均為商品質量事故違規處理通告。其中一條為賣家銷售的車載吸塵器發生燒毀、冒煙等情況&#xff0c;產生用戶人傷、財損等輿情。經查實是商家偷換關鍵部件鋰電池&#xff0c;導致商品質量下降造成事故。TEMU對于問題車載吸塵器處理結果…

opencv 存儲bgr格式/同理可類推yuv

需求背景 開發rk3588 音視頻硬件編解碼&#xff0c;然后看見他的輸入文件格式。。 只能是裸的文件。不能是壓縮過的。就是不能是jpg/png這種格式&#xff0c;只能是以下的圖像/視頻 的存儲格式.那么我沒有這個格式的&#xff0c;以前hi3559的bgr格式和他要的也不太一致&#x…

設計循環隊列,解決假溢出問題

什么是假溢出&#xff1f; 當我們使用隊列這種基本的數據結構時&#xff0c;很容易發現&#xff0c;隨著入隊和出隊操作的不斷進行&#xff0c;隊列的數據區域不斷地偏向隊尾方向移動。當我們的隊尾指針指向了隊列之外的區域時&#xff0c;我們就不能再進行入隊操作了&#xff…

單鏈表在線OJ題二(詳解+圖解)

1.在一個排序的鏈表中&#xff0c;存在重復的結點&#xff0c;請刪除該鏈表中重復的結點&#xff0c;重復的結點不保留&#xff0c;返回鏈表頭指針 本題的意思是要刪除鏈表中重復出現的節點&#xff0c;然后返回刪除重復節點后的鏈表。 我們可以直接用一個哨兵位以便于觀察鏈表…

【GIT】代碼倉庫服務器變更本地修改并推送

author: jwensh date: 20231122 問題背景 沒有使用域名的 gitlb 服務器搬移&#xff08;IP地址變了&#xff09;&#xff0c; 以至于 gitlab 管理的項目無法進行連接及推送。因為涉及到多個項目工程&#xff0c;所以可以用本地配置修改的方式來進行重新關聯&#xff08;這種修…

指針變量和地址

A.指針變量和地址 理解了內存和地址的關系&#xff0c;我們再回到C語?&#xff0c;在C語?中創建變量其實就是向內存申請空間&#xff0c;比如&#xff1a; #include <stdio.h> int main() {int a 10;return 0; } ?如&#xff0c;上述的代碼就是創建了整型變量a&…

spring-boot-admin-starter-server監控springboot項目

文章目錄 場景實現具體操作展示 場景 監控三件套Prometheus、Grafana、Alertmanager 部署起來太復雜,如果公司沒有運維而且項目很小就可以使用spring-boot-admin-starter-server替代。這個包使用起來還是很簡單的, 下面就實現一個對springCloud項目的監控 實現 參考 項目 具體操…

算法通關村第十二關|青銅|字符串轉換整數

1.轉換成小寫字母 原題&#xff1a;力扣709. 字符串大寫轉小寫有現成的API使用&#xff0c;但是我們也可以自己來實現。 使用或運算進行加操作能提高效率&#xff0c;因為 32 對應的二進制表示為 00100000 &#xff0c;而大寫字母的范圍 [65, 90] 的二進制表示在 00100000 的…

經典中的經典之字符串

前言&#xff1a;前段時間發燒了&#xff0c;所以耽誤了很多事情&#xff0c;一直沒有更新&#xff0c;多穿點衣服&#xff0c;感冒不好受。 接下來有時間就會陸續更新一些基礎的算法題&#xff0c;題目都很經典&#xff0c;大家可以先嘗試著做&#xff0c;再看 解析。 第一…

Windows常用cmd網絡命令詳解

中午好&#xff0c;我的網工朋友。 上回給你們梳理了一些有趣的cmd命令&#xff0c;很多朋友希望再拓展一下&#xff0c;這不就來了&#xff1f; 今天從windows切入&#xff0c;給你分享一些常用cmd網絡命令&#xff0c;如果能熟悉上手&#xff0c;很多功能都可以快速實現&am…

Java Class 類文件格式看這一篇就夠了

本文將揭開Java Class文件的神秘面紗&#xff0c;帶你了解Class文件的內部結構&#xff0c;并從Class文件結構的視角告訴你&#xff1a; 為什么Java Class字節碼文件可以“寫一次&#xff0c;遍地跑”&#xff1f;為什么常量池的計數從1開始&#xff0c;而不是和java等絕大多數…

封裝Redis工具類

基于StringRedisTemplate封裝一個緩存工具類&#xff0c;滿足下列需求&#xff1a; 方法1&#xff1a;將任意Java對象序列化為json并存儲在string類型的key中&#xff0c;并且可以設置TTL過期時間 方法2&#xff1a;將任意Java對象序列化為json并存儲在string類型的key中&…

【JVM精講與GC調優教程(概述)】

如何理解虛擬機(JVM)跨語言的平臺 java虛擬機根本不關心運行在其內部的程序到底是使用何種編程語言編寫的,他只關心“字節碼”文件。 java不是最強大的語言,但是JVN是最強大的虛擬機。 不存在內存溢出? 內存泄露? JAVA = (C++)–; 垃圾回收機制為我們打理了很多繁瑣的…

力扣刷題第二十八天--二叉樹

前言 今天的五道題都是層序遍歷的模板&#xff0c;深度優先的遞歸還不太熟。繼續努力。 內容 一、在每個樹行中找最大值 515.在每個樹行中找最大值 給定一棵二叉樹的根節點 root &#xff0c;請找出該二叉樹中每一層的最大值。 廣度優先搜素 時間復雜度&#xff1a;O(n)…

算法基礎:KMP算法詳細詳解

目錄 1、幾個最基本的概念 2、暴力算法 3、KMP算法 4、KMP代碼實現 5、時間復雜度 1、幾個最基本的概念 字符串的前綴&#xff1a; 主串&#xff08;目標串&#xff09;從索引0開始的子串被稱為主串的前綴。 字符串的后綴&#xff1a; 主串從索引大于0的位置到結尾的子串…

【人工智能入門學習資料福利】

總目錄如下&#xff08;部分截取&#xff09;&#xff1a; 百度網盤鏈接&#xff1a;https://pan.baidu.com/s/1bfDVG-xcPR3f3nfBJXxqQQ?pwdifu6 提取碼&#xff1a; ifu6