Vue 3新引入的Suspense組件介紹

前言

Suspense是Vue 3新增的內(nèi)置標(biāo)簽,盡管目前官方文檔里并沒(méi)有Suspense的介紹安皱,但不妨礙我們先學(xué)習(xí)它迄委。

每當(dāng)我們希望組件等待數(shù)據(jù)獲取時(shí)(通常在異步API調(diào)用中),我們都可以使用Vue3 Composition API制作異步組件信峻。

以下是異步組件有用的一些實(shí)例:

  • 在頁(yè)面加載之前顯示加載動(dòng)畫(huà)
  • 顯示占位符內(nèi)容
  • 處理延遲加載的圖像

以前,在Vue 2中祭饭,我們必須使用條件(例如 v-if 或 v-else)來(lái)檢查我們的數(shù)據(jù)是否已加載并顯示后備內(nèi)容芜茵。

但是現(xiàn)在,Suspense隨Vue3內(nèi)置了倡蝙,因此我們不必?fù)?dān)心跟蹤何時(shí)加載數(shù)據(jù)并呈現(xiàn)相應(yīng)的內(nèi)容九串。

父組件

我們通過(guò)范例學(xué)習(xí)Suspense,首先編寫(xiě)一個(gè)父組件悠咱。

  1. <template>

<template>里使用了<Suspense>標(biāo)簽蒸辆,即便你完全不懂<Suspense>的用法,看了范例也該看明白析既,default插槽里要放正式內(nèi)容,fallback插槽里要放降級(jí)內(nèi)容谆奥,我放了一行字Loading ...眼坏,你也可以放菊花圖之類(lèi)的東西。

  1. <script setup>

變量名asyncCom必須與模板里的組件名一致酸些。defineAsyncComponent方法用來(lái)動(dòng)態(tài)引入組件宰译。

<template>
  <div>
    子組件內(nèi)容:
    <Suspense>
      <template #default>
        <async-com />
      </template>
      <template #fallback>Loading ...</template>
    </Suspense>
  </div>
</template>

<script setup>
import { defineAsyncComponent } from "vue";
const asyncCom = defineAsyncComponent(() => import("./asyncCom.vue"));
</script>

子組件(asyncCom.vue)

  1. <template>沒(méi)什么可說(shuō)的。

  2. <script setup>默認(rèn)就是異步的魄懂,相當(dāng)于async setup(){}沿侈,所以你可以放心在里面寫(xiě)await。fetchData是我寫(xiě)的模擬ajax請(qǐng)求的Promise市栗。

<template>
  <div>
    <ul>
      <li v-for="item in jsonData" :key="item.name">
        {{ item.name }} - {{ item.age }}
      </li>
    </ul>
  </div>
</template>

<script setup>
import { ref } from "vue";
function fetchData() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve([
        {
          name: "張三",
          age: 15,
        },
        {
          name: "李四",
          age: 17,
        },
      ]);
    }, 1500);
  });
}

ref: jsonData = await fetchData();
</script>

效果

頁(yè)面會(huì)顯示1.5秒的Loading...缀拭,然后顯示一個(gè)列表。

原理

Vue從上到下執(zhí)行子組件的setup里的全部語(yǔ)句填帽,執(zhí)行完同步語(yǔ)句(包括await語(yǔ)句)之后蛛淋,父組件就認(rèn)為子組件加載完成,在這之前篡腌,子組件setup狀態(tài)始終未pending褐荷,所以父組件顯示降級(jí)內(nèi)容(Loading...),等子組件setup的狀態(tài)變成resolved或者rejected嘹悼,父組件就顯示默認(rèn)內(nèi)容叛甫。

捕獲異常

先說(shuō)怎么顯示異常:我的計(jì)劃是,如果出現(xiàn)異常杨伙,就不再顯示Loading...其监,而是顯示“Loading Error. Retry?”,其中Retry做成一個(gè)按鈕缀台。

現(xiàn)在ref: jsonData = await fetchData();這句根本沒(méi)有考慮異常情況棠赛,那么怎么捕獲異常呢?

父組件

我們定義一個(gè)布爾值asyncComShow負(fù)責(zé)刷新組件,同時(shí)給<async-com>綁上事件@retry="retry"睛约。retry函數(shù)要做的事情就是隱藏組件然后再顯示鼎俘,借此刷新組件。

<template>
  <div>
    <Suspense v-if="asyncComShow">
      <template #default>
        <async-com @retry="retry" />
      </template>
      <template #fallback> Loading ... </template>
    </Suspense>
  </div>
</template>

<script setup>
import { defineAsyncComponent, nextTick } from "vue";
const asyncCom = defineAsyncComponent(() => import("./asyncCom.vue"));
ref: asyncComShow = true;
function retry() {
  asyncComShow = false;
  nextTick(() => {
    asyncComShow = true;
  });
}
</script>

子組件

首先編寫(xiě)錯(cuò)誤提示辩涝,然后定義變量errorShow來(lái)切換提示贸伐。

const instance = getCurrentInstance();用于提供emit方法向父組件發(fā)出retry申請(qǐng)。也可以在頂層定義const context = useContext();怔揩,然后用context.emit("retry");捉邢,我建議用后者,因?yàn)闃?biāo)準(zhǔn)且輕量級(jí)商膊。

之后伏伐,我們用try...catch...來(lái)捕獲錯(cuò)誤。

最后晕拆,await getList()的await是必須要寫(xiě)的藐翎,不然setup生命期會(huì)在瞬間結(jié)束,Loading提示也只會(huì)顯示一瞬間实幕。

<template>
  <div>
    <ul v-if="!errorShow">
      <li v-for="item in jsonData" :key="item.name">
        {{ item.name }} - {{ item.age }}
      </li>
    </ul>
    <div v-else>
      Loading Error. <button @click="retry">Retry?</button>
    </div>
  </div>
</template>

<script setup>
import { ref, nextTick, getCurrentInstance } from "vue";

const instance = getCurrentInstance();
ref: jsonData;
ref: errorShow = false;
function fetchData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject([
        {
          name: "張三",
          age: 15,
        },
        {
          name: "李四",
          age: 17,
        },
      ]);
    }, 1500);
  });
}

function retry() {
  instance.emit("retry");
}

async function getList() {
  errorShow = false;
  try {
    jsonData = await fetchData();
  } catch (e) {
    errorShow = true;
  }
}

await getList();
</script>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末吝镣,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子昆庇,更是在濱河造成了極大的恐慌末贾,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,430評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件整吆,死亡現(xiàn)場(chǎng)離奇詭異拱撵,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)掂为,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門(mén)裕膀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人勇哗,你說(shuō)我怎么就攤上這事昼扛。” “怎么了欲诺?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,834評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵抄谐,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我扰法,道長(zhǎng)蛹含,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,543評(píng)論 1 296
  • 正文 為了忘掉前任塞颁,我火速辦了婚禮浦箱,結(jié)果婚禮上吸耿,老公的妹妹穿的比我還像新娘。我一直安慰自己酷窥,他們只是感情好咽安,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,547評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著蓬推,像睡著了一般妆棒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上沸伏,一...
    開(kāi)封第一講書(shū)人閱讀 52,196評(píng)論 1 308
  • 那天糕珊,我揣著相機(jī)與錄音,去河邊找鬼毅糟。 笑死红选,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的留特。 我是一名探鬼主播纠脾,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蜕青!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起糊渊,我...
    開(kāi)封第一講書(shū)人閱讀 39,671評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤右核,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后渺绒,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體贺喝,經(jīng)...
    沈念sama閱讀 46,221評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,303評(píng)論 3 340
  • 正文 我和宋清朗相戀三年宗兼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了躏鱼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,444評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡殷绍,死狀恐怖染苛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情主到,我是刑警寧澤茶行,帶...
    沈念sama閱讀 36,134評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站登钥,受9級(jí)特大地震影響畔师,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜牧牢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,810評(píng)論 3 333
  • 文/蒙蒙 一看锉、第九天 我趴在偏房一處隱蔽的房頂上張望姿锭。 院中可真熱鬧,春花似錦伯铣、人聲如沸呻此。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,285評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)趾诗。三九已至,卻和暖如春蹬蚁,著一層夾襖步出監(jiān)牢的瞬間恃泪,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,399評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工犀斋, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留贝乎,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,837評(píng)論 3 376
  • 正文 我出身青樓叽粹,卻偏偏與公主長(zhǎng)得像览效,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子虫几,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,455評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容