做自(zì)由與創造的先行者

Suspense

Vue.js中文(wén)手冊

實驗性功能(néng)

<Suspense> 是一項實驗性功能(néng)。它不一定會(huì)最終成爲穩定功能(néng),并且在穩定之前相關 API 也(yě)可能(néng)會(huì)發生變化。

<Suspense> 是一個内置組件,用(yòng)來(lái)在組件樹中協調對(duì)異步依賴的處理(lǐ)。它讓我們可以在組件樹上(shàng)層等待下(xià)層的多個嵌套異步依賴項解析完成,并可以在等待時(shí)渲染一個加載狀态。

異步依賴 ​

要了(le)解 <Suspense> 所解決的問題和(hé)它是如何與異步依賴進行交互的,我們需要想象這(zhè)樣一種組件層級結構:

<Suspense>

└─ <Dashboard>

├─ <Profile>

│ └─ <FriendStatus>(組件有異步的 setup())

└─ <Content>

├─ <ActivityFeed> (異步組件)

└─ <Stats>(異步組件)

在這(zhè)個組件樹中有多個嵌套組件,要渲染出它們,首先得解析一些(xiē)異步資源。如果沒有 <Suspense>,則它們每個都需要處理(lǐ)自(zì)己的加載、報(bào)錯和(hé)完成狀态。在最壞的情況下(xià),我們可能(néng)會(huì)在頁面上(shàng)看(kàn)到(dào)三個旋轉的加載态,在不同的時(shí)間顯示出内容。

有了(le) <Suspense> 組件後,我們就可以在等待整個多層級組件樹中的各個異步依賴獲取結果時(shí),在頂層展示出加載中或加載失敗的狀态。

<Suspense> 可以等待的異步依賴有兩種:

帶有異步 setup() 鈎子的組件。這(zhè)也(yě)包含了(le)使用(yòng) <script setup> 時(shí)有頂層 await 表達式的組件。

異步組件。

async setup() ​

組合式 API 中組件的 setup() 鈎子可以是異步的:

js

export default {

async setup() {

const res = await fetch(...)

const posts = await res.json()

return {

posts

}

}

}

如果使用(yòng) <script setup>,那麽頂層 await 表達式會(huì)自(zì)動讓該組件成爲一個異步依賴:

vue

<script setup>

const res = await fetch(...)

const posts = await res.json()

</script>

<template>

{{ posts }}

</template>

異步組件 ​

異步組件默認就是“suspensible”的。這(zhè)意味着如果組件關系鏈上(shàng)有一個 <Suspense>,那麽這(zhè)個異步組件就會(huì)被當作(zuò)這(zhè)個 <Suspense> 的一個異步依賴。在這(zhè)種情況下(xià),加載狀态是由 <Suspense> 控制,而該組件自(zì)己的加載、報(bào)錯、延時(shí)和(hé)超時(shí)等選項都将被忽略。

異步組件也(yě)可以通過在選項中指定 suspensible: false 表明(míng)不用(yòng) Suspense 控制,并讓組件始終自(zì)己控制其加載狀态。

加載中狀态 ​

<Suspense> 組件有兩個插槽:#default 和(hé) #fallback。兩個插槽都隻允許一個直接子節點。在可能(néng)的時(shí)候都将顯示默認槽中的節點。否則将顯示後備槽中的節點。

template

<Suspense>

<!-- 具有深層異步依賴的組件 -->

<Dashboard />

<!-- 在 #fallback 插槽中顯示 “正在加載中” -->

<template #fallback>

Loading...

</template>

</Suspense>

在初始渲染時(shí),<Suspense> 将在内存中渲染其默認的插槽内容。如果在這(zhè)個過程中遇到(dào)任何異步依賴,則會(huì)進入挂起狀态。在挂起狀态期間,展示的是後備内容。當所有遇到(dào)的異步依賴都完成後,<Suspense> 會(huì)進入完成狀态,并将展示出默認插槽的内容。

如果在初次渲染時(shí)沒有遇到(dào)異步依賴,<Suspense> 會(huì)直接進入完成狀态。

進入完成狀态後,隻有當默認插槽的根節點被替換時(shí),<Suspense> 才會(huì)回到(dào)挂起狀态。組件樹中新的更深層次的異步依賴不會(huì)造成 <Suspense> 回退到(dào)挂起狀态。

發生回退時(shí),後備内容不會(huì)立即展示出來(lái)。相反,<Suspense> 在等待新内容和(hé)異步依賴完成時(shí),會(huì)展示之前 #default 插槽的内容。這(zhè)個行爲可以通過一個 timeout prop 進行配置:在等待渲染新内容耗時(shí)超過 timeout 之後,<Suspense> 将會(huì)切換爲展示後備内容。若 timeout 值爲 0 将導緻在替換默認内容時(shí)立即顯示後備内容。

事(shì)件 ​

<Suspense> 組件會(huì)觸發三個事(shì)件:pending、resolve 和(hé) fallback。pending 事(shì)件是在進入挂起狀态時(shí)觸發。resolve 事(shì)件是在 default 插槽完成獲取新内容時(shí)觸發。fallback 事(shì)件則是在 fallback 插槽的内容顯示時(shí)觸發。

例如,可以使用(yòng)這(zhè)些(xiē)事(shì)件在加載新組件時(shí)在之前的 DOM 最上(shàng)層顯示一個加載指示器。

錯誤處理(lǐ) ​

<Suspense> 組件自(zì)身目前還不提供錯誤處理(lǐ),不過你(nǐ)可以使用(yòng) errorCaptured 選項或者 onErrorCaptured() 鈎子,在使用(yòng)到(dào) <Suspense> 的父組件中捕獲和(hé)處理(lǐ)異步錯誤。

和(hé)其他(tā)組件結合 ​

我們常常會(huì)将 <Suspense> 和(hé) <Transition>、<KeepAlive> 等組件結合。要保證這(zhè)些(xiē)組件都能(néng)正常工(gōng)作(zuò),嵌套的順序非常重要。

另外(wài),這(zhè)些(xiē)組件都通常與 Vue Router 中的 <RouterView> 組件結合使用(yòng)。

下(xià)面的示例展示了(le)如何嵌套這(zhè)些(xiē)組件,使它們都能(néng)按照預期的方式運行。若想組合得更簡單,你(nǐ)也(yě)可以删除一些(xiē)你(nǐ)不需要的組件:

template

<RouterView v-slot="{ Component }">

<template v-if="Component">

<Transition mode="out-in">

<KeepAlive>

<Suspense>

<!-- 主要内容 -->

<component :is="Component"></component>

<!-- 加載中狀态 -->

<template #fallback>

正在加載...

</template>

</Suspense>

</KeepAlive>

</Transition>

</template>

</RouterView>

Vue Router 使用(yòng)動态導入對(duì)懶加載組件進行了(le)内置支持。這(zhè)些(xiē)與異步組件不同,目前他(tā)們不會(huì)觸發 <Suspense>。但(dàn)是,它們仍然可以有異步組件作(zuò)爲後代,這(zhè)些(xiē)組件可以照常觸發 <Suspense>。

網站(zhàn)建設開(kāi)發|APP設計(jì)開(kāi)發|小(xiǎo)程序建設開(kāi)發
下(xià)一篇:單文(wén)件組件
上(shàng)一篇:Teleport