實驗性功能(néng)
<Suspense> 是一(yī)項實驗性功能(néng)。它不一(yī)定會最終成為(wèi)穩定功能(néng),并且在穩定之前相關 API 也可(kě)能(néng)會發生變化。
<Suspense> 是一(yī)個內(nèi)置組件,用來在組件樹(shù)中協調對異步依賴的處理。它讓我們可(kě)以在組件樹(shù)上(shàng)層等待下(xià)層的多個嵌套異步依賴項解析完成,并可(kě)以在等待時(shí)渲染一(yī)個加載狀态。
異步依賴
要(yào)了(le)解 <Suspense> 所解決的問(wèn)題和(hé)它是如(rú)何與異步依賴進行(xíng)交互的,我們需要(yào)想象這(zhè)樣一(yī)種組件層級結構:
<Suspense>
└─ <Dashboard>
├─ <Profile>
│ └─ <FriendStatus>(組件有異步的 setup())
└─ <Content>
├─ <ActivityFeed> (異步組件)
└─ <Stats>(異步組件)
在這(zhè)個組件樹(shù)中有多個嵌套組件,要(yào)渲染出它們,首先得解析一(yī)些異步資源。如(rú)果沒有 <Suspense>,則它們每個都(dōu)需要(yào)處理自(zì)己的加載、報錯和(hé)完成狀态。在最壞的情況下(xià),我們可(kě)能(néng)會在頁面上(shàng)看(kàn)到三個旋轉的加載态,在不同的時(shí)間(jiān)顯示出內(nèi)容。
有了(le) <Suspense> 組件後,我們就可(kě)以在等待整個多層級組件樹(shù)中的各個異步依賴獲取結果時(shí),在頂層展示出加載中或加載失敗的狀态。
<Suspense> 可(kě)以等待的異步依賴有兩種:
帶有異步 setup() 鈎子的組件。這(zhè)也包含了(le)使用 <script setup> 時(shí)有頂層 await 表達式的組件。
異步組件。
async setup()
組合式 API 中組件的 setup() 鈎子可(kě)以是異步的:
js
export default {
async setup() {
const res = await fetch(...)
const posts = await res.json()
return {
posts
}
}
}
如(rú)果使用 <script setup>,那(nà)麽頂層 await 表達式會自(zì)動讓該組件成為(wèi)一(yī)個異步依賴:
vue
<script setup>
const res = await fetch(...)
const posts = await res.json()
</script>
<template>
{{ posts }}
</template>
異步組件
異步組件默認就是“suspensible”的。這(zhè)意味着如(rú)果組件關系鏈上(shàng)有一(yī)個 <Suspense>,那(nà)麽這(zhè)個異步組件就會被當作(zuò)這(zhè)個 <Suspense> 的一(yī)個異步依賴。在這(zhè)種情況下(xià),加載狀态是由 <Suspense> 控制,而該組件自(zì)己的加載、報錯、延時(shí)和(hé)超時(shí)等選項都(dōu)将被忽略。
異步組件也可(kě)以通(tōng)過在選項中指定 suspensible: false 表明(míng)不用 Suspense 控制,并讓組件始終自(zì)己控制其加載狀态。
加載中狀态
<Suspense> 組件有兩個插槽:#default 和(hé) #fallback。兩個插槽都(dōu)隻允許一(yī)個直接子節點。在可(kě)能(néng)的時(shí)候都(dōu)将顯示默認槽中的節點。否則将顯示後備槽中的節點。
template
<Suspense>
<!-- 具有深層異步依賴的組件 -->
<Dashboard />
<!-- 在 #fallback 插槽中顯示 “正在加載中” -->
<template #fallback>
Loading...
</template>
</Suspense>
在初始渲染時(shí),<Suspense> 将在內(nèi)存中渲染其默認的插槽內(nèi)容。如(rú)果在這(zhè)個過程中遇到任何異步依賴,則會進入挂起狀态。在挂起狀态期間(jiān),展示的是後備內(nèi)容。當所有遇到的異步依賴都(dōu)完成後,<Suspense> 會進入完成狀态,并将展示出默認插槽的內(nèi)容。
如(rú)果在初次渲染時(shí)沒有遇到異步依賴,<Suspense> 會直接進入完成狀态。
進入完成狀态後,隻有當默認插槽的根節點被替換時(shí),<Suspense> 才會回到挂起狀态。組件樹(shù)中新的更深層次的異步依賴不會造成 <Suspense> 回退到挂起狀态。
發生回退時(shí),後備內(nèi)容不會立即展示出來。相反,<Suspense> 在等待新內(nèi)容和(hé)異步依賴完成時(shí),會展示之前 #default 插槽的內(nèi)容。這(zhè)個行(xíng)為(wèi)可(kě)以通(tōng)過一(yī)個 timeout prop 進行(xíng)配置:在等待渲染新內(nèi)容耗時(shí)超過 timeout 之後,<Suspense> 将會切換為(wèi)展示後備內(nèi)容。若 timeout 值為(wèi) 0 将導緻在替換默認內(nèi)容時(shí)立即顯示後備內(nèi)容。
事件
<Suspense> 組件會觸發三個事件:pending、resolve 和(hé) fallback。pending 事件是在進入挂起狀态時(shí)觸發。resolve 事件是在 default 插槽完成獲取新內(nèi)容時(shí)觸發。fallback 事件則是在 fallback 插槽的內(nèi)容顯示時(shí)觸發。
例如(rú),可(kě)以使用這(zhè)些事件在加載新組件時(shí)在之前的 DOM 最上(shàng)層顯示一(yī)個加載指示器。
錯誤處理
<Suspense> 組件自(zì)身目前還不提供錯誤處理,不過你可(kě)以使用 errorCaptured 選項或者 onErrorCaptured() 鈎子,在使用到 <Suspense> 的父組件中捕獲和(hé)處理異步錯誤。
和(hé)其他(tā)組件結合
我們常常會将 <Suspense> 和(hé) <Transition>、<KeepAlive> 等組件結合。要(yào)保證這(zhè)些組件都(dōu)能(néng)正常工(gōng)作(zuò),嵌套的順序非常重要(yào)。
另外(wài),這(zhè)些組件都(dōu)通(tōng)常與 Vue Router 中的 <RouterView> 組件結合使用。
下(xià)面的示例展示了(le)如(rú)何嵌套這(zhè)些組件,使它們都(dōu)能(néng)按照預期的方式運行(xíng)。若想組合得更簡單,你也可(kě)以删除一(yī)些你不需要(yào)的組件:
template
<RouterView v-slot="{ Component }">
<template v-if="Component">
<Transition mode="out-in">
<KeepAlive>
<Suspense>
<!-- 主要(yào)內(nèi)容 -->
<component :is="Component"></component>
<!-- 加載中狀态 -->
<template #fallback>
正在加載...
</template>
</Suspense>
</KeepAlive>
</Transition>
</template>
</RouterView>
Vue Router 使用動态導入對懶加載組件進行(xíng)了(le)內(nèi)置支持。這(zhè)些與異步組件不同,目前他(tā)們不會觸發 <Suspense>。但(dàn)是,它們仍然可(kě)以有異步組件作(zuò)為(wèi)後代,這(zhè)些組件可(kě)以照常觸發 <Suspense>。
網站建設開(kāi)發|APP設計開(kāi)發|小程序建設開(kāi)發