一个纯前端、零后端、能装到手机主屏、断网也能背的背单词工具。真正的难点不在界面,而在词库——把 5500 个词的清单,洗成一份"每一个都值得背"的清单。
我想要的东西其实很朴素:词表干净(别把 it、they 这种词也算进考研词汇)、能离线、手机点开就能背、换手机进度别丢。市面上的产品要么词库大到需要付费解锁、要么社区、打卡、商城一堆功能。
正好我手上有一份"考研英语二"的目标词表需求,于是决定自己做一套。全程用 WorkBuddy:下载和合并开源词库、写清洗脚本、生成前端页面、部署上线,都在对话里一步步推着走。
这是第一个要定的事。三条理由:
manifest.json + Service Worker,iPhone 上"添加到主屏幕"后全屏运行,有图标、有名字,看不出和原生 App 的区别。localStorage,一个请求都不往外发,不需要账号、不需要服务器,也就不存在"我的学习数据存在谁的服务器上"这个问题。代价也要说清楚:localStorage 是跟浏览器绑的,清缓存就没了。所以导出/导入备份不是"锦上添花的功能",而是必备功能——我在设置页留了「导出进度备份」,换设备前先导一份,到新设备导进去就能续着背。

第一步是找词库。我没有自己去爬,用了两份开源数据:
两份各有短板,就合并:以考研词表为主表,按单词匹配,把通用表里的词性 + 词组补进来。结果是 5530 词、释义 0 缺失,4807 个带词性、3961 个带词组。
词库里没有音标字段。我去下载了一份开源英汉词典的 CSV——约 66MB、77 万词条,然后把目标词的 phonetic 字段一条条提出来,生成一个 phonetic_map.json,前端加载词库时按词补齐。
5394 个待补词命中 5375 个。剩下 19 个是什么?ice cream、grown-up、so-called、air conditioning 这类复合词和英式拼写——大词典里收录形式不一样。这些手工补掉就行,一共 15 个。
⚠️ 有个小坑值得记一下:这份词典的音标是 ASCII 近似 IPA(比如 sә:tәn),不是标准的 Unicode IPA(ˈsɜːtn)。够用、能看懂,但不是学术标准的音标。要么接受,要么换音标源重做一遍。
"这个词怎么记"是最难自动化的部分。我最终的做法是分两类处理:
ac-(朝向、加强)+"这类提示。这类拆解是规则生成、100% 准确的,量大且不需要人工。两类合起来,主版本 2434 个词里 2329 个带背诵技巧;按类型拆是词根词缀 1686 条、谐音联想 1081 条、词组搭配 327 条。剩下的词是很短的词,本来也不需要技巧。
一开始我还想过去外部助记数据集找现成的,但那些源在当前网络环境下拿不到,最后是"程序化 + 精选"这条路把覆盖率顶到 95% 以上——反而比纯依赖外部数据更稳。
界面搭完自己用了一遍,问题立刻暴露:词太简单了。it、they、man、woman 这些词混在里面,背十条有六条是在浪费时间。
于是要做一件事:把高中及以前的词汇全部剔除。听着简单,但它有个前置问题——拿什么当"高中及以前"的判定基准?
我一开始想用词典里的 oxford(牛津 3000 核心词)和 collins(柯林斯星级)标签来筛。这是错的:牛津 3000 里包含 analyse、anticipate、career、client、capable 这类词,而这些恰恰是考研必须背的。用它当基准会大批误删核心词。
正确的基准只有一个:高考大纲词表。考纲以内的词,默认你高中就学过;考纲以外的,才是考研需要补的。
我找了两份现成的高考词表,结果发现两份都不全:
man、woman、life、hear、give 等 22 个最基础的词after(只收了 afternoon、afterward)取并集(3772 ∪ 3875 = 4029 词)之后,再手工补上 5 个漏网的介词/连词/代词(after、despite、underneath、whereas、whoever)作为兜底。
结论很朴素但很实用:"基础词表"这种东西,别信单一来源,取并集 + 人工抽查才靠谱。 这一步如果偷懒,用户背到 man 的时候就会直接卸载。
步骤 | 词数 | 说明 |
|---|---|---|
原始考研词表 | 5530 | 合并后的基准 |
去黑名单基础词 | 5395 | 早期用 135 词黑名单,剔掉 be 动词、人称代词 |
剔除高考大纲并集 | 2434 | 去掉 2905 个 + 手工补 5 个兜底,泄漏 0 |
再剔四级词(难词版) | 1150 | 用词典的 cet4 标签筛,只留六级/考研/托福/雅思及无标记难词 |
清洗前后,词库文件从 3.01MB 降到 1.30MB,少了 55%——这不只是体积问题,手机端首屏加载速度是实打实的体验差别。

复习算法用的是SM-2 间隔重复,也就是 Anki 那一套。核心逻辑不长:
上次间隔 × 难度系数 递增;其中有个容易忽略的细节:难度系数(EF)的下限是 1.3。不设下限的话,一个词反复答错会把系数压到接近 0,间隔就再也拉不长了。
交互上就是一张翻面卡片:正面单词 + 音标 + 朗读,点一下显示释义、背诵技巧和词组,再点四个评分按钮。每日计划、连续学习天数、近 30 天记忆保持率曲线、学习进度条都用 Canvas 画,没有引入任何图表库。
界面写完、语法检查通过、算法手算也对——但这不代表没 bug。下面三个都是实际用起来才发现的。
剔除词汇时,我保留了存活词的原始 id(原来是第 5000 个词,过滤后还是这个 id),好处是用户已有的学习进度不会错位。但代价是 id 变成了稀疏的——范围 54~5393,中间有 2906 个空洞。
而代码里取词原本写的是 VOCAB[id]——拿 id 当数组下标用。id 连续时这没问题,一旦 id 稀疏,取得的就是完全不相干的词。
修复是引入一张 id → 词条 的映射表,所有取词都走映射;同时在词库加载后清理已删词留下的孤儿进度,否则统计数字会把已经不存在的词算进去。
PWA 的 Service Worker 默认是缓存优先。我改完代码重新部署,用自己的电脑测一切正常——但手机上打开还是老样子。
原因很简单:sw.js 里的缓存版本号没改,Service Worker 就一直拿旧缓存里的 app.js 返回。后来定了个规矩:只要动了 app.js / style.css,缓存版本号必须 +1(v1 → v2 → v3 就是这么来的)。
如果你的 PWA 有"代码更新了但已安装用户看不到"的现象,八成是这里。
桌面浏览器上朗读正常,发到手机、从微信里打开——按了没声音。
根因是浏览器原生的 speechSynthesis 在微信内置浏览器和 iOS WebView 里经常被禁用,或者压根没有英文语音包。修法是加一条发音策略:
顺带还有个显示问题:音标里有一堆 IPA 特殊字符,某些系统字体渲染不出来,卡片上就只剩一个空的方括号。最后是靠指定一条西文字体回退链解决的。
这类问题有个共同点:桌面端测不出来。所以只要做移动端,最终必须上真机、进真实容器(微信)里点一遍。

主版本跑通后,又有个新需求:去掉四级词,只留超纲难词(适合二刷、冲刺阶段用)。
数据上的处理很简单——用词典里的 cet4 标签把四级词全部剔掉,2434 词剩 1150 词(纯六级/考研/托福/雅思及无标记难词),校验下来 0 漏删、0 误删,1150 词 100% 有音标和释义、93% 有背诵技巧。
真正要小心的是进度隔离。两版共用一套代码,如果存储键一样,用户的进度就会互相覆盖。所以我做了三重隔离:
隔离项 | 主版本 | 难词版 |
|---|---|---|
进度存储键 | ky2_state_v1 | ky2hard_state_v1 |
配置存储键 | ky2_config_v1 | ky2hard_config_v1 |
SW 缓存名 | 主版缓存 | ky2-hard-v1 |
备份文件名 | ky2_backup_* | ky2hard_backup_* |
在同一个手机上把两版都加到主屏,进度各走各的,互不影响。
两个版本都是纯静态前端,各自独立部署:主版本 2434 词,超纲难词版 1150 词。手机上用浏览器打开后「添加到主屏幕」,就是一个有图标、能全屏、断网也能背的小 App,两版可以同时装着各背各的。
两版部署后的实测数据:
指标 | 主版本 | 难词版 |
|---|---|---|
词数 | 2434 | 1150 |
音标覆盖 | 100% | 100% |
词性覆盖 | 95.5% | 91.5% |
背诵技巧覆盖 | 95.7% | 93.5% |
词组搭配 | 1734 词 | 698 词 |
词库体积 | 1.30MB | 0.58MB |
以及一条最实际的:桌面端通过 ≠ 能用。朗读哑火、音标不显示,这两个问题在电脑上永远复现不了,必须上真机、进微信里点。
本文提到的词库来自公开开源数据,仅用于个人学习用途。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。