resource-service.ts — 资源服务
文件: web/src/services/resource-service.ts
职责
本地资源加载的统一入口,负责 Hanzi Writer 笔顺数据、字源 SVG、汉字音频的加载与播放。所有资源从本地 web/src/data/ 目录加载,无 CDN 依赖。
导出的函数
Hanzi Writer 笔顺数据
getHanziWriterData(char: string): Promise<any>
获取 Hanzi Writer 笔顺数据(本地 JSON)。
- 参数:
char— 汉字字符 - 返回值: 笔顺数据对象,未找到时返回
null - 策略: LRU 缓存 → 请求去重 →
import.meta.glob查找
请求去重机制:同一汉字并发调用时共享同一个 Promise,避免重复加载。使用 _hwPending Map 管理进行中的请求,Promise 完成后自动清理。
字源 SVG
getEtymologySVGUrl(char: string, stage?: string): string
获取字源 SVG 本地 URL。
- 参数:
char— 汉字字符;stage— 书体阶段,默认"oracle"(甲骨文) - 返回值: 本地路径字符串,格式
/data/etymology-svg/{stage}/{char}.svg
getEtymologySVGFallbackUrl(char: string, stage?: string): string
获取字源 SVG 回退 URL(当前版本无 CDN 回退,始终返回空字符串)。
- 参数:
char— 汉字字符;stage— 书体阶段 - 返回值: 空字符串
""
checkEtymologyAvailable(char: string, stage?: string): Promise<boolean>
预检查某个字在指定书体下是否有可用的字源 SVG(通过 Image 预加载,3s 超时)。
- 参数:
char— 汉字字符;stage— 书体阶段,默认"oracle" - 返回值:
Promise<boolean>— 图片加载成功返回true,超时或失败返回false
fetchEtymologyIndex(): Promise<Map<string, boolean> | null>
获取字源索引(index.json),用于快速判断字源 SVG 可用性。
- 返回值:
Map<string, boolean>,key 为char|script格式,value 为可用性;加载失败返回null - 优先级: 内存缓存 → localStorage →
public/data/etymology-svg/index.json
fetchEtymologyIndexRaw(): Promise<any>
获取字源索引原始 JSON 数据(供 character.vue 使用)。
- 返回值: 完整的
index.json数据(含entries、evolutionStages、version等字段)
isEtymologyAvailableByIndex(char: string, script: string): boolean | null
通过索引缓存判断字源 SVG 可用性(零延迟,缓存未就绪时返回 null)。
- 参数:
char— 汉字字符;script— 书体脚本名 - 返回值:
true/false/null(缓存未就绪)
onEtymologySVGError(e: Event): void
处理 SVG 图片加载失败的回调(仅记录错误日志)。
- 用法:
<img :src="url" @error="onEtymologySVGError" />
isJsdelivrUrl(url: string): boolean
判断 URL 是否为 jsdelivr CDN 源(当前版本始终返回 false)。
汉字音频
getAudioUrl(pronunciation: string): string
获取汉字音频本地 URL。
- 参数:
pronunciation— 数字声调拼音,如"yi1","hao3" - 返回值: 本地路径字符串,格式
/data/hanzi-audio/{pronunciation}.mp3
getNextAudioUrl(currentUrl: string, pronunciation: string): string | null
获取下一个 CDN 音频 URL(当前版本无 CDN 回退,始终返回 null)。
playAudio(char: string, pronunciation: string): Promise<void>
播放汉字音频(本地 MP3 → TTS 降级)。
- 参数:
char— 汉字(用于 TTS 降级朗读);pronunciation— 数字声调拼音 - 降级策略: 本地 MP3 加载失败 → 浏览器 TTS(SpeechSynthesis)
播放前会停止当前正在播放的音频。TTS 降级使用 zh-CN 语音,语速 0.8。
isAudioPlaying(): boolean
检查当前是否有音频正在播放。
onAudioEnded(callback: () => void): void
注册音频播放结束回调。
资源加载策略
| 资源类型 | 策略 |
|---|---|
| HanziWriter 笔顺数据 | 本地 JSON(import.meta.glob)+ LRU 缓存 + 请求去重 |
| 字源 SVG | 本地 public/data/etymology-svg/ |
| 字源索引 | localStorage → 内存缓存 → public/data/etymology-svg/index.json |
| 汉字音频 | 本地 public/data/hanzi-audio/ → TTS 降级 |
使用示例
typescript
import { getHanziWriterData, getEtymologySVGUrl, playAudio, fetchEtymologyIndex } from "@/services/resource-service";
// 获取笔顺数据
const writerData = await getHanziWriterData("好");
// 获取字源 SVG URL
const svgUrl = getEtymologySVGUrl("好", "oracle");
// 检查字源可用性
const available = await checkEtymologyAvailable("好", "oracle");
// 获取字源索引
const index = await fetchEtymologyIndex();
// 播放汉字音频
await playAudio("好", "hao3");
// 监听播放结束
import { onAudioEnded } from "@/services/resource-service";
onAudioEnded(() => console.log("播放结束"));