【Vue.js】动态组件 & 异步组件

257 阅读3分钟

动态组件

概述:

在有一些特殊场景中,我们需要在一些位置根据不同的条件渲染不同的组件。

我们当然可以使用 v-if或者 v-show 将组件一个个写在模板上,但是如果条件越来越复杂,模板上面的判断越来越多,就会降低代码的可阅读性。

Vue 官方提出的动态组件就是为了帮助我们解决组件条件渲染的问题。

代码示例:

基本使用:

<component :is="tabs[currentTab]"></component>

这里的 is 可以是:

  • components选项中被注册的组件名
  • ES Module 导入的组件对象
  • 异步组件

解决组件频繁重新渲染的问题

当组件越来越多时,<component>中映射的组件会被频繁地切换。但是有时候,我们不希望组件频繁地被【重新渲染】

配合另外一个内置组件 <KeepAlive>可以很好地帮我们解决这个问题:

<keep-alive>
  <component :is="tabs[currentTab]"></component>
</keep-alive>

补充

关于 <component>元元素请参考:cn.vuejs.org/api/built-i…

异步组件

概述:

异步组件就是在一开始定义的时候不导入,在使用的时候再使用 HTTP 请求渲染的组件。

本质:

异步组件的本质就是一个 ES Module 的动态(组件)导入定义。

如何声明?

  • 在 Vue2 中,动态组件直接使用 ES Module 的动态导入即可:
<script>
  const Comp = () => import('@/components/Foo.vue');
</script>
  • 在 Vue3 中,动态组件需要使用 defineAsyncComponent函数进行定义:

defineAsyncComponent

接收返回 Promise<C> 的回调函数声明:

defineAsyncComponent 中传入一个返回 Promise<C>(这里的 C 为组件)的回调函数来声明一个动态组件:

import { defineAsyncComponent } from 'vue';

// 局部声明
const AsyncComp = defineAsyncComponent(() => {
  return new Promise((resolve, reject) => {
    // ...从服务器获取组件
    resolve(/* 获取到的组件 */);
    // ... 假如没有获取到,使用 reject 接收兜底的错误组件
    reject(/* 兜底错误组件 */);
  });
});
// ... 像使用其他一般组件一样使用 `AsyncComp`

// 全局声明
app.defineComponent('AsyncComp', defineAsyncComponent(() => {
  return new Promise((resolve, reject) => {
    // ...从服务器获取组件
    resolve(/* 获取到的组件 */);
    // ... 假如没有获取到,使用 reject 接收兜底的错误组件
    reject(/* 兜底错误组件 */);
  });
}))

接收动态导入声明:

和 Vue2 的语法类似,Vue3 中也可以使用动态导入来进行声明动态组件:

// 局部声明
const MyComponent = defineAsyncComponent(() =>
  import('./components/MyComponent.vue')
));

// 全局声明
app.component('MyComponent', defineAsyncComponent(() =>
  import('./components/MyComponent.vue')
));

选项精确定义:

异步操作不可避免地会涉及到加载和错误状态,因此 defineAsyncComponent() 也支持在高级选项中处理这些状态 (以官网示例举例):

const AsyncComp = defineAsyncComponent({
  // 加载函数
  loader: () => import('./Foo.vue'),

  // 加载异步组件时使用的组件
  loadingComponent: LoadingComponent,
  // 展示加载组件前的延迟时间,默认为 200ms
  delay: 200,

  // 加载失败后展示的组件
  errorComponent: ErrorComponent,
  // 如果提供了一个 timeout 时间限制,并超时了
  // 也会显示这里配置的报错组件,默认值是:Infinity
  timeout: 3000
});

配合 <Suspense>使用

异步组件默认就是“suspensible”(有悬念的)的。这意味着如果组件关系链上有一个 <Suspense>,那么这个异步组件就会被当作这个 <Suspense> 的一个异步依赖。在这种情况下,加载状态是由 <Suspense> 控制,而该组件自己的加载、报错、延时和超时等选项都将被忽略。

异步组件也可以通过在选项中指定 suspensible: false 表明不用 Suspense 控制,并让组件始终自己控制其加载状态。

具体参考:cn.vuejs.org/guide/built…