前言

前端开发经常遇到异步的问题,请求函数,链接库,等,都有可能需要通过promise或者async await 来进行异步的一个封装。

异步组件也由此诞生,我用settimeout来模拟一个vue3的异步组件

异步的子组件

<template>
  <div>{{ someData }}</div>
</template>

<script lang="ts">
import { ref } from 'vue'
import { Data } from './types/index'

export default {
  setup(props: Data) {
    const someData = ref('dx')
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        return resolve({ someData })
      }, 3000)
    })
  }
}
</script>

按照正常组件使用

<template>
  <div class="about">
    <h1>This is an about page</h1>
    <Child />
  </div>
</template>

<script lang="ts">
import Child from '@/components/template/Template.vue'
export default {
  components: {
    Child
  }
}
</script>

页面会有警告,而且组件渲染也失败了,解析了警告的意思,是说这种异步组件需要一个Suspense来包裹一下
在这里插入图片描述
Suspense 是vue3新增的一个内置组件,专门用来处理异步组件的。

异步组件的正确使用方式

<template>
  <div class="about">
    <h1>This is an about page</h1>
    <Suspense>
      <template v-slot:default>
        <Child />
      </template>
      <template v-slot:fallback>
        <h3>请稍等</h3>
      </template>
    </Suspense>
    <!-- <Child /> -->
  </div>
</template>

<script lang="ts">
import { defineAsyncComponent } from 'vue'
// import Child from '@/components/template/Template.vue'
const Child = defineAsyncComponent(() => import('@/components/template/Template.vue'))
export default {
  components: {
    Child
  }
}
</script>

Suspense的原理是通过插槽来实现的,一个default和一个fallback。
default里面放置异步组件,fallback里面就放置异步组件未渲染之前的一个样式

有人说vue3中setup不能是异步函数,上面的代码证明,setup可以是异步函数,他们可能不了解Suspense这个内置组件。

async await 的setup函数

<template>
  <div>{{ someData }}</div>
</template>

<script lang="ts">
import { ref } from 'vue'
import { Data } from './types/index'

export default {
  async setup(props: Data) {
    const currentInstance: ComponentInternalInstance | null = getCurrentInstance()
    const someData = ref('dx')
    const result = await new Promise((resolve, reject) => {
      setTimeout(() => {
        return resolve({ someData })
      }, 3000)
    })
    return result
  }
}
</script>

父组件通过Suspense使用异步的子组件

<template>
  <div class="about">
    <h1>This is an about page</h1>
    <Suspense>
      <template v-slot:default>
        <Child />
      </template>
      <template v-slot:fallback>
        <h3>请稍等</h3>
      </template>
    </Suspense>
    <!-- <Child /> -->
  </div>
</template>

<script lang="ts">
import { defineAsyncComponent } from 'vue'
// import Child from '@/components/template/Template.vue'
const Child = defineAsyncComponent(() => import('@/components/template/Template.vue'))
export default {
  components: {
    Child
  }
}
</script>

最后总结一下,只要将异步组件放在suspense的default插槽中即可。

扩展阅读

在 Vue 3 中,异步组件的加载方式与 Vue 2 有一些不同。Vue 3 引入了 Suspense 特性,使异步组件的加载和处理更为灵活和直观。以下是如何在 Vue 3 中使用异步组件:

  1. 使用 defineAsyncComponent 函数

    Vue 3 提供了一个函数 defineAsyncComponent,用于定义异步加载的组件。你可以使用这个函数来创建一个异步组件,然后在需要的地方加载它。

    <template>
      <div>
        <button @click="loadComponent">Load Component</button>
        <Suspense>
          <AsyncComponent v-if="isComponentLoaded" />
          <template #fallback>Loading...</template>
        </Suspense>
      </div>
    </template>
    
    <script>
    import { defineAsyncComponent, ref } from 'vue';
    
    const AsyncComponent = defineAsyncComponent(() =>
      import('./AsyncComponent.vue')
    );
    
    export default {
      components: {
        AsyncComponent,
      },
      setup() {
        const isComponentLoaded = ref(false);
    
        const loadComponent = () => {
          isComponentLoaded.value = true;
        };
    
        return { isComponentLoaded, loadComponent };
      },
    };
    </script>
    

    在上面的代码中,我们使用 defineAsyncComponent 创建了一个异步组件,并在按钮点击时加载它。Suspense 组件用于处理异步加载时的状态,<template #fallback> 标签中的内容会在组件加载期间显示。

  2. 使用 defineAsyncComponent 的工厂函数形式

    你也可以使用工厂函数形式的 defineAsyncComponent 来动态指定要加载的组件,这对于根据条件加载不同的组件很有用。

    <template>
      <div>
        <button @click="loadComponentA">Load Component A</button>
        <button @click="loadComponentB">Load Component B</button>
        <Suspense>
          <DynamicAsyncComponent v-if="isComponentLoaded" />
          <template #fallback>Loading...</template>
        </Suspense>
      </div>
    </template>
    
    <script>
    import { defineAsyncComponent, ref } from 'vue';
    
    const DynamicAsyncComponent = defineAsyncComponent(() =>
      import(/* webpackChunkName: "dynamic-async" */ `./DynamicAsyncComponent.vue`)
    );
    
    export default {
      components: {
        DynamicAsyncComponent,
      },
      setup() {
        const isComponentLoaded = ref(false);
    
        const loadComponentA = () => {
          DynamicAsyncComponent.resolveComponent(() =>
            import(`./ComponentA.vue`)
          );
          isComponentLoaded.value = true;
        };
    
        const loadComponentB = () => {
          DynamicAsyncComponent.resolveComponent(() =>
            import(`./ComponentB.vue`)
          );
          isComponentLoaded.value = true;
        };
    
        return { isComponentLoaded, loadComponentA, loadComponentB };
      },
    };
    </script>
    

在这个示例中,我们创建了一个名为 DynamicAsyncComponent 的异步组件,并使用 DynamicAsyncComponent.resolveComponent 方法动态指定要加载的组件。

异步组件的加载和管理在 Vue 3 中更为直观和灵活,可以更好地处理动态加载和懒加载组件的需求。
在这里插入图片描述

Logo

基于 Vue 的企业级 UI 组件库和中后台系统解决方案,为数万开发者服务。

更多推荐