likes
comments
collection
share

重学 Vu3 之异步组件

作者站长头像
站长
· 阅读数 42

基本用法

在大型项目中,一个应用往往需要拆分成多个模块,一般不会同时加载所有的模块。Vue 提供了 defineAsyncComponent 方法,用于异步加载组件,也就是说只有当需要该组件的时候才会从服务器中加载。

defineAsyncComponent 函数可以接收一个返回 promise 组件的函数,import 方法也是返回 promise,所以下面的例子使用了 import 导入组件。

<!-- index.html -->
<div id="app"></div>

<script type="module">
  import { createApp, h, defineAsyncComponent } from "https://unpkg.com/vue@3/dist/vue.esm-browser.js";

  createApp({
    data() {
      return {
        show: false,
      };
    },
    render() {
      return h("div", [
        h("button", { onClick: () => (this.show = !this.show) }, "show"),
        this.show && h(defineAsyncComponent(() => import("./my-component.js"))),
      ]);
    },
  }).mount("#app");
</script>
// my-component.js
export default {
  data() {
    return {
      info: "wow",
    };
  },
  template: `<div>{{ info }}</div>`,
};

重学 Vu3 之异步组件

从上面的例子可以看出,在根组件创建了一个 show 按钮,点击之后就会使用 defineAsyncComponent 方法从 my-component.js 文件中获取到对应的组件。从控制台可以看出,my-component.js 文件并不是刚开始就从服务器加载出来的,而是当用户点击按钮之后才从服务器获取到该文件。

<!-- index.html -->
<div id="app"></div>

<script type="module">
  import { createApp, h, defineAsyncComponent } from "https://unpkg.com/vue@3/dist/vue.esm-browser.js";
  import MyComponent from "./my-component.js";

  createApp({
    data() {
      return {
        show: false,
      };
    },
    render() {
      return h("div", [h("button", { onClick: () => (this.show = !this.show) }, "show"), this.show && h(MyComponent)]);
    },
  }).mount("#app");
</script>

重学 Vu3 之异步组件

上面的例子在原来例子的基础上做了修改,不再使用 defineAsyncComponent 函数导入组件,在控制台可以看出 my-component.js 文件一开始就会从服务器中获取。

需要补充说明的是,之前写的文章示例都是使用在线开发环境完成的,这次也尝试使用这种形式,但是出现了报错 Async component loader resolved to undefined. If you are using retry(), make sure to return its return value,查找相关资料,原来这是一个已知的问题,在 GitHub 中有这个 issue

加载和错误处理

defineAsyncComponent 函数不但可以支持一个函数作为参数,也支持对象作为传参。

function defineAsyncComponent(
  source: AsyncComponentLoader | AsyncComponentOptions
): Component

type AsyncComponentLoader = () => Promise<Component>

interface AsyncComponentOptions {
  loader: AsyncComponentLoader
  loadingComponent?: Component
  errorComponent?: Component
  delay?: number
  timeout?: number
  suspensible?: boolean
  onError?: (
    error: Error,
    retry: () => void,
    fail: () => void,
    attempts: number
  ) => any
}

loader 属性值是一个返回 promise 组件的函数,delay 属性用于支持延迟加载的毫秒数,loadingComponent 属性用于延迟加载时显示提示组件,timeout 属性可以设置超时的毫秒数,errorComponent 属性用于组件加载出错时显示提示组件。

<!-- index.html -->
<div id="app"></div>

<script type="module">
  import { createApp, h, defineAsyncComponent } from "https://unpkg.com/vue@3/dist/vue.esm-browser.js";

  createApp({
    data() {
      return {
        show: false,
      };
    },
    render() {
      return h("div", [
        h("button", { onClick: () => (this.show = !this.show) }, "show"),
        this.show &&
          h(
            defineAsyncComponent({
              loader: () =>
                new Promise((resolve) => {
                  setTimeout(() => {
                    resolve(() => h("div", "asyncComponent"));
                  }, 3000);
                }),
              delay: 1000,
              loadingComponent: h("div", "loading"),
              errorComponent: h("div", "error"),
              timeout: 4000,
            })
          ),
      ]);
    },
  }).mount("#app");
</script>

重学 Vu3 之异步组件

在上面的示例中,点击 show 按钮,延迟一秒出现 loadingComponent,3秒后出现 loader 函数对应的组件。

结论

Vue3 通过 defineAsyncComponent 函数来支持异步组件,该函数既支持传入一个返回 promise 组件的函数,也支持传入一个多选项的对象。使用异步组件后可以实现按需从服务器获取对应组件,提高性能。

参考资料

vue 中文官网

转载自:https://juejin.cn/post/7222529227677270072
评论
请登录