Vue 3 渲染机制解密:从模板到页面的魔法

news2025/1/15 20:53:24

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 在数据更新后获取更新后的 DOM
    this.$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.coloradmin.cn/o/1239982.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

sonar对webgoat进行静态扫描

安装sonar并配置 docker安装sonarqube&#xff0c;sonarQube静态代码扫描 - Joson6350 - 博客园 (cnblogs.com) 对webgoat进行sonar扫描 扫描结果 bugs Change this condition so that it does not always evaluate to "false" 意思是这里的else if语句不会执行…

git merge 和 git rebase

一、是什么 在使用 git 进行版本管理的项目中&#xff0c;当完成一个特性的开发并将其合并到 master 分支时&#xff0c;会有两种方式&#xff1a; git merge git rebasegit rebase 与 git merge都有相同的作用&#xff0c;都是将一个分支的提交合并到另一分支上&#xff0c;…

Redis的持久化(新)

Redis中数据都保存在内存&#xff0c;但是内存中的数据变换很快&#xff0c;也很容易丢失&#xff0c;比如连接断开、宕机停机等等。而Redis提供的数据持久化机制有RDB(Redis DataBase)和AOF(Append Only File)。 1.RDB RDB是指在指定的时间间隔内将内存中的数据集快照写入到磁…

static和extern

1.extern extern 是⽤来声明外部符号的&#xff0c;如果⼀个全局的符号在A⽂件中定义的&#xff0c;在B⽂件中想使⽤&#xff0c;就可以使⽤ extern 进⾏声明&#xff0c;然后使⽤。 即在一个源文件中想要使用另一个源文件&#xff0c;即可通过这个extern来声明使用。 2.st…

NC65 修改元数据字段长度

NC65 修改元数据字段长度&#xff0c;执行下面sql&#xff0c;执行完后需要重启NC服务才生效。 --属性 update md_property set attrlength 200 where name fphm and classidece96dd8-bdf8-4db3-a112-9d2f636d388f ;--列 update md_column set columnlength 200 where tab…

Java的判空

校验List 在进行参数非空校验时&#xff0c;我们总是容易直接就对任何的东西都来一个&#xff01; null 其实这样并不完全正确&#xff0c;对list类型来说 不等于null和list.size ! 0是不一样的。 不等于null是指已经声明了list的存在&#xff0c;并且在堆内存中有了引用。 …

ROS设置DHCP option121

配置时&#xff0c;了解格式很关键&#xff0c;16进制填写格式如下&#xff1a; 将要访问的IPV&#xff14;地址&#xff1a;192.168.100.0/24 192.168.30.254 转换为&#xff1a;掩码 目标网段 网关 0x18c0a864c0a81efe&#xff0c;0不用填写 ROS配置如下图&#xff1a; 抓…

【Qt开发流程】之富文本处理

描述 Scribe框架提供了一组类&#xff0c;用于读取和操作结构化的富文本文档。与Qt中以前的富文本支持不同&#xff0c;新的类集中在QTextDocument类上&#xff0c;而不是原始文本信息。这使开发者能够创建和修改结构化的富文本文档&#xff0c;而不必准备中间标记格式的内容。…

修改 OkHttp3 的超时时间

修改 OkHttp3 的超时时间 一. 前言二. 导入mavengradle 三. 设置超时时间 一. 前言 OkHttp是一个处理网络请求的开源项目,是安卓端最火热的轻量级框架,由移动支付Square公司开发。OkHttp3是Java和Android都能用&#xff0c;Android还有一个著名网络库叫Volley&#xff0c;那个…

关于用css设置input输入框hover的时候的样式以及当input为disabled的时候,不要让hover样式生效

效果如果&#xff1a; 编辑状态下的时候&#xff1a; 只读状态下的时候&#xff1a; 代码如图&#xff1a; <input type"text" name"dataForm.exportCode" id"exportCodeItem" required :disabled"editDisabled" />input:not(…

Web自动化测试流程:从入门到精通,帮你成为测试专家!

Web应用程序在今天的软件开发中占据着越来越重要的地位。保证Web应用程序的质量和稳定性是非常必要的&#xff0c;而自动化测试是一种有效的方法。本文将介绍Web自动化测试流程&#xff0c;并提供代码示例。 步骤一&#xff1a;选取测试工具 选择适合自己团队的自动化测试工具…

UML建模图文详解教程——用例图

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl本文参考资料&#xff1a;《UML面向对象分析、建模与设计&#xff08;第2版&#xff09;》吕云翔&#xff0c;赵天宇 著 用例图概述 用例图(use case diagram)是表示一个系统…

【数据结构】链表中二级指针的应用

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:数据结构 ⚙️操作环境:Visual Studio 2022 (注:为方便演示本篇使用的x86系统,因此指针的大小为4个字节) 目录 &#x1f4cc;形参的改变不影响实参! 1.调用函数更改整型时传值调用与传址调用的区别 &#x1f38f;传值…

【Pytorch】Visualization of Fature Maps(2)

学习参考来自 使用CNN在MNIST上实现简单的攻击样本https://github.com/wmn7/ML_Practice/blob/master/2019_06_03/CNN_MNIST%E5%8F%AF%E8%A7%86%E5%8C%96.ipynb 文章目录 在 MNIST 上实现简单的攻击样本1 训练一个数字分类网络2 控制输出的概率, 看输入是什么3 让正确的图片分…

表格制作软件排行榜,热门做表格的软件推荐

在数字化时代&#xff0c;表格不仅仅是企业管理和数据整理的重要工具&#xff0c;更是学术研究、项目规划以及日常生活中必不可少的一部分。为了更高效地进行表格制作&#xff0c;选择一款优秀的表格制作软件是至关重要的。在众多的软件中&#xff0c;我们特别推荐一款备受好评…

【电路笔记】-电流源

电流源 文章目录 电流源1、概述1.1 理想电流源1.2 实际电流源1.3 连接规则 2、依赖电流2.1 压控电流源2.2 电流控制电流源 3、总结 本文为前面文章 电压源的延续&#xff0c;我们将在本文介绍电流源。 与电压源的情况类似&#xff0c;我们将首先介绍理想电流源的概念&#xff…

基于springboot实现摄影跟拍预定管理系统【项目源码+论文说明】计算机毕业设计

基于springboot实现摄影跟拍预定管理系统演示 摘要 首先,论文一开始便是清楚的论述了系统的研究内容。其次,剖析系统需求分析,弄明白“做什么”,分析包括业务分析和业务流程的分析以及用例分析,更进一步明确系统的需求。然后在明白了系统的需求基础上需要进一步地设计系统,主要…

【Redis】持久化-RDBAOF混合持久化

文章目录 前置知识RDB&#xff08;定期备份&#xff09;触发机制流程说明RDB文件的处理RDB 的优缺点 AOF&#xff08;实时备份&#xff09;使用AOF命令写入AOF工作流程文件同步重写机制重写触发机制AOF进制重写流程 混合持久化启动时数据恢复 总结 前置知识 回顾MySQL MySQL的事…

UVM项目笔记——通过寄存器模型实现AHB接口的寄存器读写(内含源码)

目录 1.前言 2.DRIVER实现 2.1 AHB二级流水时序 2.2 “队列错位法”实现driver 2.3 driver代码 2.4 仿真log与波形 2.5 多级流水拓展方法 1.前言 UVM driver在接口协议的实现中起着非常重要的作用&#xff0c;因为它一端处理基于类的事务级sequence&#xff0c;另一端处…

Wagtail-基于Python Django的内容管理系统CMS如何实现公网访问

Wagtail-基于Python Django的内容管理系统CMS实现公网访问 文章目录 Wagtail-基于Python Django的内容管理系统CMS实现公网访问前言1. 安装并运行Wagtail1.1 创建并激活虚拟环境 2. 安装cpolar内网穿透工具3. 实现Wagtail公网访问4. 固定的Wagtail公网地址 前言 Wagtail是一个…