何時使用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); onErrorCaptured(e=>{ errMsg.value="出錯了" return true //必須return true上傳上去才能使用 }) return{errMsg} } } </script> <style scoped> </style>
此時我們把async2.vue中的地址寫錯,我們打開瀏覽器可以看到顯示了錯誤信息,提示我們接口是錯誤的
上面的示例中,我們顯示的后備預顯示的內容,直接解決了異步操作,如果出了什么問題被拒絕,使用onErrorCaptured鈎子捕獲錯誤,將其傳遞給errMsg屬性並在模板中顯示,而不是回退內容