前端开发经常遇到异步的问题,请求函数,链接库,等,都有可能需要通过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插槽中即可。