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
| 名稱 | 類型 | 必填 | 預設值 | 說明 |
|---|---|---|---|---|
imgKey | string | ✓ | — | AES 解密金鑰。沿用 SwImage 同名 prop,與 useSystemStore().info.img_key 對齊;非加密路徑下不會被使用,但仍需傳值 |
url | string | '' | 文字 URL。含 .bnc 走解密分支,否則直接當 UTF-8 文字讀取 |
Events
| 事件名 | 載荷 | 說明 |
|---|---|---|
update:resp | resp: string | 文字載入完成(含快取命中)後觸發。從 null 變為 string 時只觸發一次,再次切換 url 重新載入完成又會觸發 |
Slots
| 插槽名 | 作用域參數 | 說明 |
|---|---|---|
default | { text: string | null } | 作用域插槽。text === null 表示載入中(或 SSR 階段),string 表示已就緒 |
工作原理
- SSR 短路:
import.meta.client為false時直接回傳null,不發起任何網路請求與解密 - 快取查詢:
fileId = md5(url.pathname),先查 IndexedDBtext表;命中直接TextDecoder().decode(bytes)回傳 - 遠端載入 + 條件解密:未命中則
fetch(url)拿到ArrayBuffer;URL 含.bnc走aes.decrypt(buf, imgKey)→ 否則直接new Uint8Array(buf) - 寫快取 + 通知:解密後的位元組寫入 IndexedDB(下次秒開),同時
result從null→string,觸發update:resp事件 - 響應式重載:
watchEffect監聽props.url,變化時清狀態重新走流程
底層通用邏輯封裝在 useDecryptedAsset composable,SwAsyncText 與 SwImage 共享同一套 fetch + 條件解密 + 快取 + 狀態機。
注意事項
imgKey建議透過useRuntimeConfig().public.cacheAesKey傳入,不要硬編碼金鑰- 作用域插槽中
text === null是載入中狀態,text === ''是「載入完成但內容為空字串」,注意區分 - 元件僅在用戶端執行,SSR 階段插槽收到的
text始終為null,請提供骨架佔位 update:resp事件快取命中也會觸發——對呼叫方更一致(任何「載入完成」都通知),但首屏統計 PV 時要去重