引子

我最近开发了一个牛津5000词学习网页(在线体验),这是一个基于Web的英语词汇学习工具,集成了单词查询、例句学习、发音播放和学习进度跟踪等功能。本文将详细分享整个项目的技术实现过程。

过程

获取单词列表

牛津词典的官方网页提供了 ox5000 词表,他们对于这份词表的定义是:The most important words to learn in English.
https://www.oxfordlearnersdictionaries.com/wordlists/oxford3000-5000

你可以使用下面的提四次获取一段JS代码,在上面的网页中按F12在控制台中运行。

1
2
3
4
5
帮我把下面的思路直接写一小段 js 来获取这个词表的 json 版本:
筛选展开,选择 5000词,然后右击某一行单词,审查元素发现其位置为 `#wordlistsContentPanel > ul > li`
于是查找所有同类元素发现共5948个,`document.querySelectorAll("#wordlistsContentPanel > ul > li")`
我们需要遍历每一个 li 元素,获取 li.attrs['data-hw']作为单词,li.attrs['data-ox5000']作为 CEFR_level, 获取 li.querySelector(".pos").textContent 作为词性 part_of_speech,并整理为对象:{"word":li.attrs['data-hw'], "CEFR_level":li.attrs['data-ox5000'], "part_of_speech"}
收集所有对象后,我们需要压缩数据集为列表形式: [["word", "CEFR_level", "part_of_speech"],...] 并导出为 the_oxford_5000_list.json

我使用 deepseek 得到的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 获取所有li元素
const liElements = document.querySelectorAll("#wordlistsContentPanel > ul > li");

// 将NodeList转换为数组并处理每个元素
const wordData = Array.from(liElements).map(li => {
return {
word: li.getAttribute('data-hw'),
CEFR_level: li.getAttribute('data-ox5000'),
part_of_speech: li.querySelector(".pos")?.textContent?.trim() || ''
};
});

// 转换为列表形式 [["word", "CEFR_level", "part_of_speech"], ...]
const listData = wordData.map(item => [item.word, item.CEFR_level, item.part_of_speech]);

// 创建JSON字符串
const jsonData = JSON.stringify(listData, null, 2);

// 创建Blob对象并下载
const blob = new Blob([jsonData], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'the_oxford_5000_list.json';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);

console.log(`已处理 ${wordData.length} 个单词,文件已开始下载。`);

最终呈现为一个静态资源 API
GET https://cdn.imhcg.cn/apps/words/the_oxford_5000_list.json
Output:
[["word", "CEFR_level", "part_of_speech"],...]

获取单词例句列表

我希望用大语言模型为每个单词生成例句,然后把这些例句提前缓存好,给页面查询。
核心的系统提示词为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
你是一位精通史蒂芬·克拉申"可理解输入"理论的语言习得专家。你的任务是基于用户提供的词汇数据,生成大量可理解、且有意义的句子,以帮助用户通过暴露于可理解输入(i+1水平)来自然习得该单词和常见用法,最终促进英语整体习得。

词汇数据以JSON格式提供,例如:```{
"word": "abandon",
"ox3000": "b2",
"ox5000": "b2",
"pos": "verb"
}```。其中,ox3000和ox5000表示单词的CEFR级别(如b2为中级),pos表示词性。

请严格遵循以下原则生成句子:
- **可理解性**:句子必须使用简单、清晰的语言,确保略高于用户当前水平(i+1),但不会造成理解障碍。参考ox3000/ox5000级别调整句子复杂度(例如,B2级别使用中等难度结构,避免高级语法)。
- **有意义性**:句子必须嵌入真实、有趣的语境中,避免孤立或机械重复。理想情况下,句子应形成一个连贯的叙事、故事或日常场景,以增强记忆和习得。
- **习得导向**:专注于自然暴露单词的常见用法(如搭配、短语动词等),不提供显性语法解释或翻译,以降低情感过滤。
- **数量与多样性**:生成10-15个句子,覆盖单词的不同常见用法(例如,作为动词时,包括及物用法、常见宾语等),生成的句子要从简单到困难,一开始需要是简单句。
- **输出格式**:输出JSON格式的句子列表,格式为 [{"en":"sentence1","zh":"sentence1_chinese_translate"},...]。不添加任何额外评论、解释或元信息。

基于用户提供的具体词汇数据,立即生成句子。

然后我整理为了这样的接口供前端调用

GET https://cdn.imhcg.cn/apps/words/kv/?db=the_oxford_5000_sentences.db&name=vocabulary&key={word}-{part_of_speech}

Example: https://cdn.imhcg.cn/apps/words/kv/?db=the_oxford_5000_sentences.db&name=vocabulary&key=hello-noun

Output:
{"success":true,"message":"","data":{"key":"hello-noun","value":"[\n {\"en\": \"Hello is a friendly word.\", \"zh\": \"Hello\u662f\u4e00\u4e2a\u53cb\u597d\u7684\u8bcd\u3002\"}]"}}

json.loads(data.value) = [{"en_sentence", "zh_sentence_translation"},...]

获取例句发音

例句发音使用 Kokoro 来本地生成上一步每个例句的发音,以每个句子的 md5 小写值作为文件名,并提前存储到服务器,供前端调用。

GET https://cdn.imhcg.cn/apps/words/the_oxford_5000_voice/{md5(en_sentence)}.mp3

Example: https://cdn.imhcg.cn/apps/words/the_oxford_5000_voice/0a0a0ab163c3b23ded0e40ffc519f1c9.mp3

Output: audio bytes

获取释义

释义来自于开源的 mdx 电子词典数据,我下载了 非常庞大的数据,使用python提起了音标、基础释义及动词变体,存入了 sqlite 数据库,然后我整理为了这样的接口供前端调用。

GET https://cdn.imhcg.cn/apps/words/kv/?db=the_oxford_5000_words.db&name=words&key={word}

Example: https://cdn.imhcg.cn/apps/words/kv/?db=the_oxford_5000_words.db&name=words&key=hello

Output:
{"success":true,"message":"","data":{"key":"hello","value":"{\"word\": \"hello\", \"ipa\": \"[h\\u0259'l\\u0259\\u028a]\", \"frms\": null, \"dcbs\": [[\"n.\", \"\\u8868\\u793a\\u95ee\\u5019\\uff0c \\u60ca\\u5947\\u6216\\u5524\\u8d77\\u6ce8\\u610f\\u65f6\\u7684\\u7528\\u8bed\"], [\"int.\", \"\\u5582\\uff1b\\u54c8\\u7f57\"], [\"n.\", \"(Hello)\\u4eba\\u540d\\uff1b(\\u6cd5)\\u57c3\\u6d1b\"]], \"ox3000\": \"a1\", \"ox5000\": \"a1\", \"pos\": \"noun\"}"}}

json.loads(data.value) = {"word", "ipa", "frms":"仅在动词时提供一个数组,成员为动词变体字符串", "dcbs":"可能是长度为2的数组,此时第一个元素为词性简称(需要加衬底展示),第二个元素为用法。如果数组长度不为2,直接以;拼接为文本显示。", "ox3000", "ox5000", "pos"}

最后,把上面的文档和下面的提示词发给 AI 生成前端页面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88

你是一个网页专家,
请你使用文档中的接口,
为我做一个网页,
具体需求为:

### 1. 数据加载与显示
- 页面加载时显示加载中状态
- 从CDN获取牛津5000单词列表(GET https://cdn.imhcg.cn/apps/words/the_oxford_5000_list.json)
- 显示单词、难度等级和词性
- 完整显示所有符合条件的单词(无数量限制)

### 2. 筛选功能
- 难度筛选器(A1-C1 + 所有难度)
- 词性筛选器(动态加载所有词性 + 所有词性)
- 筛选器左右分布在一行
- 单词卡片水平布局,单词在左,难度词性在右

### 3. 单词详情功能
- 点击单词弹出模态框
- 显示单词释义(音标、词性、中文解释)(GET https://cdn.imhcg.cn/apps/words/kv/?db=the_oxford_5000_words.db&name=words&key={word})
- 显示单词例句(中英文对照)(https://cdn.imhcg.cn/apps/words/kv/?db=the_oxford_5000_sentences.db&name=vocabulary&key={word}-{part_of_speech})
- 音标与单词标题在同一行显示

### 4. 音频播放功能
- 例句右侧显示播放按钮
- 点击播放例句发音(GET https://cdn.imhcg.cn/apps/words/the_oxford_5000_voice/{md5(en_sentence)}.mp3)
- 播放时图标变为停止图标
- 同时只能播放一个音频
- 音频播放完成自动恢复播放图标

### 5. 学习记录系统,基于 Localstorage
- 单词所有例句播放完成后标记为已学习
- 弹出Toast提示"已学习 {word}"
- 已学习单词存入localStorage
- 渲染时自动隐藏已学习单词
- 正确显示当前筛选条件下的已学习单词数量

### 6. 学习记录管理,基于 Localstorage
- 页面底部添加"清理学习记录"链接
- 点击后弹出确认对话框
- 确认后清空所有学习记录
- 清理后重新渲染单词列表

## 用户体验需求

### 7. 动画与交互
- 使用贝塞尔曲线实现流畅动画
- 单词卡片悬停效果
- 播放按钮缩放和颜色变化
- 加载动画包含旋转效果
- 模态框头部固定定位

### 8. 视觉设计
- iOS风格简洁设计
- 淡雅的配色方案(半透明颜色)
- 圆角卡片和阴影效果
- 响应式布局适配移动端
- 播放按钮状态颜色区分(播放中红色,已播放绿色)

### 9. 性能优化
- 使用防抖技术减少频繁渲染
- DocumentFragment批量DOM操作
- 并行获取单词释义和例句
- 硬件加速动画
- 本地存储减少重复请求

## 数据持久化需求

### 10. 本地存储
- 记忆用户筛选偏好(难度和词性)
- 默认值:难度A1,词性verb
- 存储已学习单词列表
- 页面刷新后保持用户设置

## 技术实现需求

### 11. 第三方库使用
- Bootstrap 5 - UI框架
- Font Awesome - 图标
- CryptoJS - MD5计算(用于音频URL)

### 12. API集成
- 单词列表API
- 单词释义API
- 单词例句API
- 例句发音API