SwAsyncText

非同步載入遠端文字元件。URL 含 .bnc 時走 AES 解密路徑,否則直接當 UTF-8 文字讀取,業務方傳 url 即可,加密分流由元件內部自動處理。fileId = md5(url.pathname) 寫入 IndexedDB text 表持久化快取,命中即回傳;監聽 url 變化自動重新載入,天然適配章節切換等場景。

基礎用法

使用作用域插槽接收載入結果。text 為 null 時表示載入中,string 時表示已就緒(含快取命中)。

基礎用法(非加密)

加载中...
<template>
  <SwAsyncText :url="textUrl" :img-key="aesKey">
    <template #default="{ text }">
      <div v-if="text === null" class="loading">載入中…</div>
      <article v-else>{{ text }}</article>
    </template>
  </SwAsyncText>
</template>

<script setup lang="ts">
const textUrl = '/articles/welcome.txt'
const aesKey = useRuntimeConfig().public.cacheAesKey
</script>

加密內容(.bnc 分流)

下面是真實加密的演示資源(chapter-secret.bnc 用與 demo imgKey 配套的金鑰加密):非同步取回密文 → 用戶端 AES 解密 → 展示明文。

加密內容:非同步解密成功展示

加载中...

URL 含 .bnc 副檔名時自動走 AES 解密路徑。imgKey 沿用 SwImage 同名 prop,與 useSystemStore().info.img_key 欄位對齊;非加密路徑下 imgKey 仍需傳值(滿足 prop 必填),但內部不會被使用。

<template>
  <SwAsyncText :url="chapter.url" :img-key="aesKey">
    <template #default="{ text }">
      <div v-if="text === null" class="skeleton" />
      <article v-else v-html="text" />
    </template>
  </SwAsyncText>
</template>

<script setup lang="ts">
// chapter.url 例如:https://cdn.example.com/novel/chap-001.bnc
const aesKey = useRuntimeConfig().public.cacheAesKey
</script>

章節切換自動重新載入

url prop 變化時元件自動重新請求並解密,無需手動重置狀態,適合翻頁閱讀器場景。

章節切換

加载中...

監聽載入完成事件

@update:resp 在文字載入完成後觸發(含快取命中),用於字數統計、閱讀進度回報等後續動作。

監聽載入事件 + 字數統計

加载中...

Props

名稱類型必填預設值說明
imgKeystring✓—AES 解密金鑰。沿用 SwImage 同名 prop,與 useSystemStore().info.img_key 對齊;非加密路徑下不會被使用,但仍需傳值
urlstring''文字 URL。含 .bnc 走解密分支,否則直接當 UTF-8 文字讀取

Events

事件名載荷說明
update:respresp: string文字載入完成(含快取命中)後觸發。從 null 變為 string 時只觸發一次,再次切換 url 重新載入完成又會觸發

Slots

插槽名作用域參數說明
default{ text: string | null }作用域插槽。text === null 表示載入中(或 SSR 階段),string 表示已就緒

工作原理

  1. SSR 短路:import.meta.client 為 false 時直接回傳 null,不發起任何網路請求與解密
  2. 快取查詢:fileId = md5(url.pathname),先查 IndexedDB text 表;命中直接 TextDecoder().decode(bytes) 回傳
  3. 遠端載入 + 條件解密:未命中則 fetch(url) 拿到 ArrayBuffer;URL 含 .bnc 走 aes.decrypt(buf, imgKey) → 否則直接 new Uint8Array(buf)
  4. 寫快取 + 通知:解密後的位元組寫入 IndexedDB(下次秒開),同時 result 從 null → string,觸發 update:resp 事件
  5. 響應式重載:watchEffect 監聽 props.url,變化時清狀態重新走流程

底層通用邏輯封裝在 useDecryptedAsset composable,SwAsyncText 與 SwImage 共享同一套 fetch + 條件解密 + 快取 + 狀態機。

注意事項

  • imgKey 建議透過 useRuntimeConfig().public.cacheAesKey 傳入,不要硬編碼金鑰
  • 作用域插槽中 text === null 是載入中狀態,text === '' 是「載入完成但內容為空字串」,注意區分
  • 元件僅在用戶端執行,SSR 階段插槽收到的 text 始終為 null,請提供骨架佔位
  • update:resp 事件快取命中也會觸發——對呼叫方更一致(任何「載入完成」都通知),但首屏統計 PV 時要去重