何时使用Suspense
在vue2.0时代我们必须使用条件(v-if或v-else)来检查我们的数据是否已加载并显示后备内容。
在vue3.0中内置了Suspense,因此我们不必担心何时加载数据并呈现相应的内容
Suspense是什么
Suspense组件作用是当你在进行一个异步加载时,先提供一些静态组件作为显示内容,然后当异步加载完毕时再显示
Suspense组件会暂停你的组件渲染,重现一个回落组件,直到满足条件为止。
Suspense的使用
Suspense组件是vue3推出的一个内置特殊组件,只是一个内置标签,不需要引入直接使用就可以,必须需要返回一个Promise,而不是json对象
Suspense组件是一个具有插槽的组件,是根据插槽机制来区分组件的,#default插槽内容是你需要渲染的异步组件(需要返回一个promise);#fallback是你指定的加载中的静态组件
defineComponent:defineComponent是用来解决在Typescript环境中,传统的Vue.extend无法对组件给出正确的类型判断,也就是说在Typescript环境中如果参数类型不正确时,用defineComponent()组件来进行包装函数
<template> <div> </div> </template> <script> import {defineComponent} from "vue" export default defineComponent ({ }) </script> <style scoped> </style>
app.vue
<template> <div> <Suspense> <template #default> <!--#default插槽内容是你需要渲染的异步组件(需要返回一个promise)--> <async></async> </template> <template #fallback><!--#fallback是你指定的加载中的静态组件--> loading... </template> </Suspense> </div> </template> <script> import async from "./components/async.vue" export default { components:{ async } } </script> <style scoped> </style>
async.vue
<template> <div> {{result}} </div> </template> <script> import {defineComponent} from "vue" export default defineComponent ({ setup(){ return new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve({result:'hello'}) },2000) }) } }) </script> <style scoped> </style>
此时我们打开浏览器发现在前2秒,定时器还没有工作时加载的是指定的加载中的静态组件loading...,2秒钟过会才会加载出hello
Suspense组件使用步骤:
1>新建一个异步组件,需要返回一个promise
2>将异步组件包装在<template #default>标签中
3>在异步组件旁边添加一个兄弟组件标签为<template #fallback>
4>将两个组件包装在<Suspense>组件中
Suspense加载多个组件
我们新建一个async.vue组件
<template> <div> <ul> <li v-for="(item,index) in result" :key="index">{{item.title}}</li> </ul> </div> </template> <script> import {defineComponent} from "vue" import axios from "axios" export default defineComponent ({ async setup(){ let data=await axios.get("http://jsonplaceholder.typicode.com/posts?userId=2") //一个开源的接口地址 console.log(data) return {result:data.data} } }) </script> <style scoped> </style>
app.vue
<template> <div> <Suspense> <template #default> <!--#default插槽内容是你需要渲染的异步组件(需要返回一个promise)--> <async></async> <async2></async2> </template> <template #fallback><!--#fallback是你指定的加载中的静态组件--> loading... </template> </Suspense> </div> </template> <script> import async from "./components/async.vue" import async2 from "./components/async2.vue" export default { components:{ async, async2 } } </script> <style scoped> </style>
此时页面会弹出一个警告
警告: Suspense是一个实验性的特性,它的API可能会改变slots,除非只有一个根节点
怎么解决:异步组件外增加一个div包裹(增加一个根节点)
<template> <div> <Suspense> <template #default> <!--#default插槽内容是你需要渲染的异步组件(需要返回一个promise)--> <div> <async></async> <async2></async2> </div> </template> <template #fallback><!--#fallback是你指定的加载中的静态组件--> loading... </template> </Suspense> </div> </template>
此时就不会报错
如果我们一步请求失败会怎么办呢?
Suspense可以捕获组件错误
使用新的onErrorCaptured生命周期钩子来捕获此类错误并显示正确的错误信息
在vue.中,使用onErrorCaptured钩子函数,无论调用什么,此钩子函数会在捕获的组件的错误时运行,如果出现问题,我们可以将其余的suspense一起使用以渲染错误
app.vue
<template> <div> <div v-if="errMsg">{{errMsg}}</div> <Suspense v-else> <template #default> <!--#default插槽内容是你需要渲染的异步组件(需要返回一个promise)--> <div> <async></async> <async2></async2> </div> </template> <template #fallback><!--#fallback是你指定的加载中的静态组件--> loading... </template> </Suspense> </div> </template> <script> import async from "./components/async.vue" import async2 from "./components/async2.vue" import {onErrorCaptured,ref} from "vue" export default { components:{ async, async2 }, setup(){ let errMsg=ref(null); one rrorCaptured(e=>{ errMsg.value="出错了" return true //必须return true上传上去才能使用 }) return{errMsg} } } </script> <style scoped> </style>
此时我们把async2.vue中的地址写错,我们打开浏览器可以看到显示了错误信息,提示我们接口是错误的
上面的示例中,我们显示的后备预显示的内容,直接解决了异步操作,如果出了什么问题被拒绝,使用onErrorCaptured钩子捕获错误,将其传递给errMsg属性并在模板中显示,而不是回退内容