本项目站内源代码下载地址
技术栈:Next.js 16 + React 19 + TypeScript + Tailwind CSS v4 + shadcn/ui + Zustand + Framer Motion
目标平台:Web(PWA/移动端优先)





1. 项目概述
1.1 项目定位
本项目是一款面向考研(研究生入学考试)英语备考的词汇闪卡学习工具,采用移动端优先的交互设计,支持:
- 闪卡记忆:3D翻转卡片展示单词、音标、释义、真题例句与记忆锚点
- 单词列表:分类浏览、搜索、收藏、掌握/熟悉标记
- 测验模式:四选一选择题,自动从同分类中生成干扰项
- 学习统计:今日进度、总体掌握率、分类进度、每日目标设定
1.2 核心特性
| 特性 | 说明 |
|---|---|
| 词汇覆盖 | 约 5500+ 考研大纲词汇,分核心词、阅读高频、完形高频、写作加分、基础词五大类 |
| 多分类标签 | 每个单词可属于多个分类(如核心词同时标记为阅读/写作) |
| 数据去重 | 14 个数据源按优先级合并,保留最详细的词条信息 |
| 本地持久化 | 学习进度、收藏、测验成绩通过 localStorage 持久化 |
| 每日目标 | 支持 20/30/50/80/100 词每日学习目标,自动跨天重置 |
| 交互动画 | 卡片翻转、页面切换、进度条动画均采用 Framer Motion |
2. 系统架构
2.1 整体架构图
#mermaid-svg-QV430reJVRVR5ZrW{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-QV430reJVRVR5ZrW .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-QV430reJVRVR5ZrW .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-QV430reJVRVR5ZrW .error-icon{fill:#552222;}#mermaid-svg-QV430reJVRVR5ZrW .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-QV430reJVRVR5ZrW .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-QV430reJVRVR5ZrW .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-QV430reJVRVR5ZrW .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-QV430reJVRVR5ZrW .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-QV430reJVRVR5ZrW .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-QV430reJVRVR5ZrW .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-QV430reJVRVR5ZrW .marker{fill:#333333;stroke:#333333;}#mermaid-svg-QV430reJVRVR5ZrW .marker.cross{stroke:#333333;}#mermaid-svg-QV430reJVRVR5ZrW svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-QV430reJVRVR5ZrW p{margin:0;}#mermaid-svg-QV430reJVRVR5ZrW .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-QV430reJVRVR5ZrW .cluster-label text{fill:#333;}#mermaid-svg-QV430reJVRVR5ZrW .cluster-label span{color:#333;}#mermaid-svg-QV430reJVRVR5ZrW .cluster-label span p{background-color:transparent;}#mermaid-svg-QV430reJVRVR5ZrW .label text,#mermaid-svg-QV430reJVRVR5ZrW span{fill:#333;color:#333;}#mermaid-svg-QV430reJVRVR5ZrW .node rect,#mermaid-svg-QV430reJVRVR5ZrW .node circle,#mermaid-svg-QV430reJVRVR5ZrW .node ellipse,#mermaid-svg-QV430reJVRVR5ZrW .node polygon,#mermaid-svg-QV430reJVRVR5ZrW .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-QV430reJVRVR5ZrW .rough-node .label text,#mermaid-svg-QV430reJVRVR5ZrW .node .label text,#mermaid-svg-QV430reJVRVR5ZrW .image-shape .label,#mermaid-svg-QV430reJVRVR5ZrW .icon-shape .label{text-anchor:middle;}#mermaid-svg-QV430reJVRVR5ZrW .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-QV430reJVRVR5ZrW .rough-node .label,#mermaid-svg-QV430reJVRVR5ZrW .node .label,#mermaid-svg-QV430reJVRVR5ZrW .image-shape .label,#mermaid-svg-QV430reJVRVR5ZrW .icon-shape .label{text-align:center;}#mermaid-svg-QV430reJVRVR5ZrW .node.clickable{cursor:pointer;}#mermaid-svg-QV430reJVRVR5ZrW .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-QV430reJVRVR5ZrW .arrowheadPath{fill:#333333;}#mermaid-svg-QV430reJVRVR5ZrW .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-QV430reJVRVR5ZrW .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-QV430reJVRVR5ZrW .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-QV430reJVRVR5ZrW .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-QV430reJVRVR5ZrW .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-QV430reJVRVR5ZrW .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-QV430reJVRVR5ZrW .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-QV430reJVRVR5ZrW .cluster text{fill:#333;}#mermaid-svg-QV430reJVRVR5ZrW .cluster span{color:#333;}#mermaid-svg-QV430reJVRVR5ZrW div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-QV430reJVRVR5ZrW .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-QV430reJVRVR5ZrW rect.text{fill:none;stroke-width:0;}#mermaid-svg-QV430reJVRVR5ZrW .icon-shape,#mermaid-svg-QV430reJVRVR5ZrW .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-QV430reJVRVR5ZrW .icon-shape p,#mermaid-svg-QV430reJVRVR5ZrW .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-QV430reJVRVR5ZrW .icon-shape .label rect,#mermaid-svg-QV430reJVRVR5ZrW .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-QV430reJVRVR5ZrW .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-QV430reJVRVR5ZrW .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-QV430reJVRVR5ZrW :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 外部依赖
客户端 (Next.js App Router)
persist
UI 层
src/app/page.tsx
组件层
src/components/ui/*
状态管理层
Zustand + persist
数据层
src/data/*
Hooks 层
src/hooks/*
Tailwind CSS v4
Framer Motion
Lucide Icons
shadcn/ui
localStorage
2.2 技术栈明细
| 层级 | 技术选型 | 版本 | 用途 |
|---|---|---|---|
| 框架 | Next.js | 16.1.1 | React 全栈框架,App Router |
| 运行时 | React | 19.0.0 | UI 库 |
| 语言 | TypeScript | 5.x | 类型安全 |
| 样式 | Tailwind CSS | 4.x | 原子化 CSS |
| UI 组件 | shadcn/ui | latest | Radix UI 封装组件库 |
| 状态管理 | Zustand | 5.0.6 | 轻量级全局状态 |
| 动画 | Framer Motion | 12.23.2 | 交互动画 |
| 图标 | Lucide React | 0.525.0 | 矢量图标 |
| 构建 | Bun | 1.3.4 | 包管理与运行时 |
| ORM | Prisma | 6.11.1 | 数据库模型(当前未深度使用) |
| 数据库 | SQLite | - | 本地数据库(当前未深度使用) |
3. 目录结构
考研词汇练习/
├── src/
│ ├── app/
│ │ ├── api/route.ts # API 路由(占位)
│ │ ├── globals.css # Tailwind 主题与 CSS 变量
│ │ ├── layout.tsx # 根布局(字体、Metadata)
│ │ └── page.tsx # 主页面(单页应用,含所有 Tab)
│ ├── components/ui/ # shadcn/ui 组件(~50 个)
│ │ ├── button.tsx
│ │ ├── card.tsx
│ │ ├── input.tsx
│ │ ├── progress.tsx
│ │ ├── badge.tsx
│ │ ├── scroll-area.tsx
│ │ ├── separator.tsx
│ │ └── ...
│ ├── data/ # 词汇数据源(14 个文件)
│ │ ├── vocabulary.ts # 核心词汇(最详细,40+ 词,含例句)
│ │ ├── vocab-core-ae.ts # 核心词 A-E
│ │ ├── vocab-core-fn.ts # 核心词 F-N
│ │ ├── vocab-core-oz.ts # 核心词 O-Z
│ │ ├── vocab-core-expanded.ts
│ │ ├── vocab-ac.ts # A-C 补充词
│ │ ├── vocab-dh.ts # D-H 补充词
│ │ ├── vocab-io.ts # I-O 补充词
│ │ ├── vocab-ps.ts # P-S 补充词
│ │ ├── vocab-tz.ts # T-Z 补充词
│ │ ├── vocab-extra.ts
│ │ ├── vocab-supplement-al.ts
│ │ ├── vocab-supplement-mz.ts
│ │ ├── vocab-rcw.ts
│ │ ├── vocab-final-supplement.ts
│ │ └── index.ts # 数据聚合与去重逻辑
│ ├── store/
│ │ └── vocab-store.ts # Zustand 全局状态
│ └── hooks/
│ ├── use-mobile.ts # 移动端检测
│ └── use-toast.ts # Toast 通知
├── prisma/
│ └── schema.prisma # 数据库模型(User, Post)
├── public/
│ ├── logo.svg
│ └── robots.txt
├── scripts/
│ └── gen-vocab.js # 词汇生成脚本
├── .zscripts/ # 自定义脚本(build/dev/start)
├── next.config.ts # Next.js 配置(standalone 输出)
├── components.json # shadcn/ui 配置
├── package.json
├── bun.lock
└── Caddyfile # Caddy 反向代理配置
4. 数据模型设计
4.1 词汇数据模型
#mermaid-svg-swoNr5wlslxHdgyp{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-swoNr5wlslxHdgyp .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-swoNr5wlslxHdgyp .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-swoNr5wlslxHdgyp .error-icon{fill:#552222;}#mermaid-svg-swoNr5wlslxHdgyp .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-swoNr5wlslxHdgyp .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-swoNr5wlslxHdgyp .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-swoNr5wlslxHdgyp .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-swoNr5wlslxHdgyp .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-swoNr5wlslxHdgyp .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-swoNr5wlslxHdgyp .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-swoNr5wlslxHdgyp .marker{fill:#333333;stroke:#333333;}#mermaid-svg-swoNr5wlslxHdgyp .marker.cross{stroke:#333333;}#mermaid-svg-swoNr5wlslxHdgyp svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-swoNr5wlslxHdgyp p{margin:0;}#mermaid-svg-swoNr5wlslxHdgyp g.classGroup text{fill:#9370DB;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-swoNr5wlslxHdgyp g.classGroup text .title{font-weight:bolder;}#mermaid-svg-swoNr5wlslxHdgyp .cluster-label text{fill:#333;}#mermaid-svg-swoNr5wlslxHdgyp .cluster-label span{color:#333;}#mermaid-svg-swoNr5wlslxHdgyp .cluster-label span p{background-color:transparent;}#mermaid-svg-swoNr5wlslxHdgyp .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-swoNr5wlslxHdgyp .cluster text{fill:#333;}#mermaid-svg-swoNr5wlslxHdgyp .cluster span{color:#333;}#mermaid-svg-swoNr5wlslxHdgyp .nodeLabel,#mermaid-svg-swoNr5wlslxHdgyp .edgeLabel{color:#131300;}#mermaid-svg-swoNr5wlslxHdgyp .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-swoNr5wlslxHdgyp .label text{fill:#131300;}#mermaid-svg-swoNr5wlslxHdgyp .labelBkg{background:#ECECFF;}#mermaid-svg-swoNr5wlslxHdgyp .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-swoNr5wlslxHdgyp .classTitle{font-weight:bolder;}#mermaid-svg-swoNr5wlslxHdgyp .node rect,#mermaid-svg-swoNr5wlslxHdgyp .node circle,#mermaid-svg-swoNr5wlslxHdgyp .node ellipse,#mermaid-svg-swoNr5wlslxHdgyp .node polygon,#mermaid-svg-swoNr5wlslxHdgyp .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-swoNr5wlslxHdgyp .divider{stroke:#9370DB;stroke-width:1;}#mermaid-svg-swoNr5wlslxHdgyp g.clickable{cursor:pointer;}#mermaid-svg-swoNr5wlslxHdgyp g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-swoNr5wlslxHdgyp g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-swoNr5wlslxHdgyp .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-swoNr5wlslxHdgyp .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-swoNr5wlslxHdgyp .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-swoNr5wlslxHdgyp .dashed-line{stroke-dasharray:3;}#mermaid-svg-swoNr5wlslxHdgyp .dotted-line{stroke-dasharray:1 2;}#mermaid-svg-swoNr5wlslxHdgyp #compositionStart,#mermaid-svg-swoNr5wlslxHdgyp .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-swoNr5wlslxHdgyp #compositionEnd,#mermaid-svg-swoNr5wlslxHdgyp .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-swoNr5wlslxHdgyp #dependencyStart,#mermaid-svg-swoNr5wlslxHdgyp .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-swoNr5wlslxHdgyp #dependencyStart,#mermaid-svg-swoNr5wlslxHdgyp .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-swoNr5wlslxHdgyp #extensionStart,#mermaid-svg-swoNr5wlslxHdgyp .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-swoNr5wlslxHdgyp #extensionEnd,#mermaid-svg-swoNr5wlslxHdgyp .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-swoNr5wlslxHdgyp #aggregationStart,#mermaid-svg-swoNr5wlslxHdgyp .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-swoNr5wlslxHdgyp #aggregationEnd,#mermaid-svg-swoNr5wlslxHdgyp .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-swoNr5wlslxHdgyp #lollipopStart,#mermaid-svg-swoNr5wlslxHdgyp .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-swoNr5wlslxHdgyp #lollipopEnd,#mermaid-svg-swoNr5wlslxHdgyp .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-swoNr5wlslxHdgyp .edgeTerminals{font-size:11px;line-height:initial;}#mermaid-svg-swoNr5wlslxHdgyp .classTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-swoNr5wlslxHdgyp .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-swoNr5wlslxHdgyp .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-swoNr5wlslxHdgyp :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} belongs to
VocabWord
+string id
+string word
+string phonetic
+string coreMeaning
+string exampleEn
+string exampleCn
+string memoryTip
+string category
+string\[\] categories
+string\[\] tags
+number frequency
+number mastery
Category
+string key
+string label
+Icon icon
+string color
4.2 词汇字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
id |
string |
唯一标识,格式 w{序号} |
word |
string |
英文单词 |
phonetic |
string |
音标(IPA) |
coreMeaning |
string |
核心中文释义 |
exampleEn |
string |
真题例句(英文) |
exampleCn |
string |
真题例句(中文翻译) |
memoryTip |
string |
记忆提示/锚点 |
category |
enum |
主分类:core/reading/cloze/writing/basic |
categories |
string[] |
自动分配的多个分类标签 |
tags |
string[] |
词性标签:动词/名词/形容词/高频/搭配 等 |
frequency |
number |
考频等级 1-5 |
mastery |
number |
掌握等级 0-2(当前未使用) |
4.3 状态管理模型(Zustand Store)
#mermaid-svg-bEWBnsvqiYGttaQF{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-bEWBnsvqiYGttaQF .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-bEWBnsvqiYGttaQF .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-bEWBnsvqiYGttaQF .error-icon{fill:#552222;}#mermaid-svg-bEWBnsvqiYGttaQF .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-bEWBnsvqiYGttaQF .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-bEWBnsvqiYGttaQF .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-bEWBnsvqiYGttaQF .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-bEWBnsvqiYGttaQF .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-bEWBnsvqiYGttaQF .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-bEWBnsvqiYGttaQF .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-bEWBnsvqiYGttaQF .marker{fill:#333333;stroke:#333333;}#mermaid-svg-bEWBnsvqiYGttaQF .marker.cross{stroke:#333333;}#mermaid-svg-bEWBnsvqiYGttaQF svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-bEWBnsvqiYGttaQF p{margin:0;}#mermaid-svg-bEWBnsvqiYGttaQF g.classGroup text{fill:#9370DB;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-bEWBnsvqiYGttaQF g.classGroup text .title{font-weight:bolder;}#mermaid-svg-bEWBnsvqiYGttaQF .cluster-label text{fill:#333;}#mermaid-svg-bEWBnsvqiYGttaQF .cluster-label span{color:#333;}#mermaid-svg-bEWBnsvqiYGttaQF .cluster-label span p{background-color:transparent;}#mermaid-svg-bEWBnsvqiYGttaQF .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-bEWBnsvqiYGttaQF .cluster text{fill:#333;}#mermaid-svg-bEWBnsvqiYGttaQF .cluster span{color:#333;}#mermaid-svg-bEWBnsvqiYGttaQF .nodeLabel,#mermaid-svg-bEWBnsvqiYGttaQF .edgeLabel{color:#131300;}#mermaid-svg-bEWBnsvqiYGttaQF .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-bEWBnsvqiYGttaQF .label text{fill:#131300;}#mermaid-svg-bEWBnsvqiYGttaQF .labelBkg{background:#ECECFF;}#mermaid-svg-bEWBnsvqiYGttaQF .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-bEWBnsvqiYGttaQF .classTitle{font-weight:bolder;}#mermaid-svg-bEWBnsvqiYGttaQF .node rect,#mermaid-svg-bEWBnsvqiYGttaQF .node circle,#mermaid-svg-bEWBnsvqiYGttaQF .node ellipse,#mermaid-svg-bEWBnsvqiYGttaQF .node polygon,#mermaid-svg-bEWBnsvqiYGttaQF .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-bEWBnsvqiYGttaQF .divider{stroke:#9370DB;stroke-width:1;}#mermaid-svg-bEWBnsvqiYGttaQF g.clickable{cursor:pointer;}#mermaid-svg-bEWBnsvqiYGttaQF g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-bEWBnsvqiYGttaQF g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-bEWBnsvqiYGttaQF .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-bEWBnsvqiYGttaQF .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-bEWBnsvqiYGttaQF .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-bEWBnsvqiYGttaQF .dashed-line{stroke-dasharray:3;}#mermaid-svg-bEWBnsvqiYGttaQF .dotted-line{stroke-dasharray:1 2;}#mermaid-svg-bEWBnsvqiYGttaQF #compositionStart,#mermaid-svg-bEWBnsvqiYGttaQF .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-bEWBnsvqiYGttaQF #compositionEnd,#mermaid-svg-bEWBnsvqiYGttaQF .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-bEWBnsvqiYGttaQF #dependencyStart,#mermaid-svg-bEWBnsvqiYGttaQF .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-bEWBnsvqiYGttaQF #dependencyStart,#mermaid-svg-bEWBnsvqiYGttaQF .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-bEWBnsvqiYGttaQF #extensionStart,#mermaid-svg-bEWBnsvqiYGttaQF .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-bEWBnsvqiYGttaQF #extensionEnd,#mermaid-svg-bEWBnsvqiYGttaQF .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-bEWBnsvqiYGttaQF #aggregationStart,#mermaid-svg-bEWBnsvqiYGttaQF .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-bEWBnsvqiYGttaQF #aggregationEnd,#mermaid-svg-bEWBnsvqiYGttaQF .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-bEWBnsvqiYGttaQF #lollipopStart,#mermaid-svg-bEWBnsvqiYGttaQF .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-bEWBnsvqiYGttaQF #lollipopEnd,#mermaid-svg-bEWBnsvqiYGttaQF .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-bEWBnsvqiYGttaQF .edgeTerminals{font-size:11px;line-height:initial;}#mermaid-svg-bEWBnsvqiYGttaQF .classTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-bEWBnsvqiYGttaQF .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-bEWBnsvqiYGttaQF .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-bEWBnsvqiYGttaQF :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} VocabStore
+string currentCategory
+number currentWordIndex
+boolean isFlipped
+string\[\] masteredWords
+string\[\] familiarWords
+string\[\] bookmarkedWords
+number quizScore
+number quizTotal
+number quizCurrentIndex
+boolean quizAnswered
+number quizSelectedAnswer
+string searchQuery
+string learningMode
+number dailyGoal
+number dailyLearned
+string dailyDate
+setCategory(category)
+nextWord()
+prevWord()
+flipCard()
+markMastered(wordId)
+markFamiliar(wordId)
+toggleBookmark(wordId)
+submitQuizAnswer(selected, correct)
+incrementDailyLearned()
+getStats()
4.4 数据持久化流程
localStorage persist 中间件 Zustand Store 页面组件 用户 localStorage persist 中间件 Zustand Store 页面组件 用户 #mermaid-svg-0RljfSSnVTRx9GVZ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-0RljfSSnVTRx9GVZ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-0RljfSSnVTRx9GVZ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-0RljfSSnVTRx9GVZ .error-icon{fill:#552222;}#mermaid-svg-0RljfSSnVTRx9GVZ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-0RljfSSnVTRx9GVZ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-0RljfSSnVTRx9GVZ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-0RljfSSnVTRx9GVZ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-0RljfSSnVTRx9GVZ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-0RljfSSnVTRx9GVZ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-0RljfSSnVTRx9GVZ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-0RljfSSnVTRx9GVZ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-0RljfSSnVTRx9GVZ .marker.cross{stroke:#333333;}#mermaid-svg-0RljfSSnVTRx9GVZ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-0RljfSSnVTRx9GVZ p{margin:0;}#mermaid-svg-0RljfSSnVTRx9GVZ .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-0RljfSSnVTRx9GVZ text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-0RljfSSnVTRx9GVZ .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-0RljfSSnVTRx9GVZ .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-0RljfSSnVTRx9GVZ .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-0RljfSSnVTRx9GVZ .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-0RljfSSnVTRx9GVZ #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-0RljfSSnVTRx9GVZ .sequenceNumber{fill:white;}#mermaid-svg-0RljfSSnVTRx9GVZ #sequencenumber{fill:#333;}#mermaid-svg-0RljfSSnVTRx9GVZ #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-0RljfSSnVTRx9GVZ .messageText{fill:#333;stroke:none;}#mermaid-svg-0RljfSSnVTRx9GVZ .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-0RljfSSnVTRx9GVZ .labelText,#mermaid-svg-0RljfSSnVTRx9GVZ .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-0RljfSSnVTRx9GVZ .loopText,#mermaid-svg-0RljfSSnVTRx9GVZ .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-0RljfSSnVTRx9GVZ .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-0RljfSSnVTRx9GVZ .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-0RljfSSnVTRx9GVZ .noteText,#mermaid-svg-0RljfSSnVTRx9GVZ .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-0RljfSSnVTRx9GVZ .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-0RljfSSnVTRx9GVZ .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-0RljfSSnVTRx9GVZ .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-0RljfSSnVTRx9GVZ .actorPopupMenu{position:absolute;}#mermaid-svg-0RljfSSnVTRx9GVZ .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-0RljfSSnVTRx9GVZ .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-0RljfSSnVTRx9GVZ .actor-man circle,#mermaid-svg-0RljfSSnVTRx9GVZ line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-0RljfSSnVTRx9GVZ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 标记单词为"已掌握" markMastered(wordId) 更新 masteredWords 数组 状态变更触发持久化 序列化并写入 vocab-store 确认存储 完成 状态更新,UI 重渲染
5. 页面与组件设计
5.1 页面结构
本项目采用**单页应用(SPA)**模式,所有功能集中在 page.tsx 中,通过底部 Tab Bar 切换视图。
#mermaid-svg-8DPZGMHkQUmEZ5e9{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-8DPZGMHkQUmEZ5e9 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .error-icon{fill:#552222;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .marker.cross{stroke:#333333;}#mermaid-svg-8DPZGMHkQUmEZ5e9 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-8DPZGMHkQUmEZ5e9 p{margin:0;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .cluster-label text{fill:#333;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .cluster-label span{color:#333;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .cluster-label span p{background-color:transparent;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .label text,#mermaid-svg-8DPZGMHkQUmEZ5e9 span{fill:#333;color:#333;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .node rect,#mermaid-svg-8DPZGMHkQUmEZ5e9 .node circle,#mermaid-svg-8DPZGMHkQUmEZ5e9 .node ellipse,#mermaid-svg-8DPZGMHkQUmEZ5e9 .node polygon,#mermaid-svg-8DPZGMHkQUmEZ5e9 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .rough-node .label text,#mermaid-svg-8DPZGMHkQUmEZ5e9 .node .label text,#mermaid-svg-8DPZGMHkQUmEZ5e9 .image-shape .label,#mermaid-svg-8DPZGMHkQUmEZ5e9 .icon-shape .label{text-anchor:middle;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .rough-node .label,#mermaid-svg-8DPZGMHkQUmEZ5e9 .node .label,#mermaid-svg-8DPZGMHkQUmEZ5e9 .image-shape .label,#mermaid-svg-8DPZGMHkQUmEZ5e9 .icon-shape .label{text-align:center;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .node.clickable{cursor:pointer;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .arrowheadPath{fill:#333333;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-8DPZGMHkQUmEZ5e9 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8DPZGMHkQUmEZ5e9 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-8DPZGMHkQUmEZ5e9 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .cluster text{fill:#333;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .cluster span{color:#333;}#mermaid-svg-8DPZGMHkQUmEZ5e9 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-8DPZGMHkQUmEZ5e9 rect.text{fill:none;stroke-width:0;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .icon-shape,#mermaid-svg-8DPZGMHkQUmEZ5e9 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .icon-shape p,#mermaid-svg-8DPZGMHkQUmEZ5e9 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .icon-shape .label rect,#mermaid-svg-8DPZGMHkQUmEZ5e9 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8DPZGMHkQUmEZ5e9 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-8DPZGMHkQUmEZ5e9 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-8DPZGMHkQUmEZ5e9 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} VocabApp (page.tsx)
单词子模式
Tab 内容区
FlashcardTab
闪卡模式
底部导航栏
TabBar
HomeTab
首页
WordsTab
单词
QuizMode
测验
ProfileTab
我的
WordListTab
列表模式
5.2 底部导航栏
| Tab | 图标 | 标签 | 功能 |
|---|---|---|---|
| home | Home |
首页 | 学习概览、今日推荐、分类入口 |
| words | BookOpen |
单词 | 闪卡/列表模式切换 |
| quiz | Brain |
测验 | 四选一选择题测验 |
| profile | User |
我的 | 学习统计、进度、设置 |
5.3 首页(HomeTab)
#mermaid-svg-14fuhXDnBjGvv8Qn{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-14fuhXDnBjGvv8Qn .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-14fuhXDnBjGvv8Qn .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-14fuhXDnBjGvv8Qn .error-icon{fill:#552222;}#mermaid-svg-14fuhXDnBjGvv8Qn .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-14fuhXDnBjGvv8Qn .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-14fuhXDnBjGvv8Qn .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-14fuhXDnBjGvv8Qn .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-14fuhXDnBjGvv8Qn .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-14fuhXDnBjGvv8Qn .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-14fuhXDnBjGvv8Qn .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-14fuhXDnBjGvv8Qn .marker{fill:#333333;stroke:#333333;}#mermaid-svg-14fuhXDnBjGvv8Qn .marker.cross{stroke:#333333;}#mermaid-svg-14fuhXDnBjGvv8Qn svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-14fuhXDnBjGvv8Qn p{margin:0;}#mermaid-svg-14fuhXDnBjGvv8Qn .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-14fuhXDnBjGvv8Qn .cluster-label text{fill:#333;}#mermaid-svg-14fuhXDnBjGvv8Qn .cluster-label span{color:#333;}#mermaid-svg-14fuhXDnBjGvv8Qn .cluster-label span p{background-color:transparent;}#mermaid-svg-14fuhXDnBjGvv8Qn .label text,#mermaid-svg-14fuhXDnBjGvv8Qn span{fill:#333;color:#333;}#mermaid-svg-14fuhXDnBjGvv8Qn .node rect,#mermaid-svg-14fuhXDnBjGvv8Qn .node circle,#mermaid-svg-14fuhXDnBjGvv8Qn .node ellipse,#mermaid-svg-14fuhXDnBjGvv8Qn .node polygon,#mermaid-svg-14fuhXDnBjGvv8Qn .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-14fuhXDnBjGvv8Qn .rough-node .label text,#mermaid-svg-14fuhXDnBjGvv8Qn .node .label text,#mermaid-svg-14fuhXDnBjGvv8Qn .image-shape .label,#mermaid-svg-14fuhXDnBjGvv8Qn .icon-shape .label{text-anchor:middle;}#mermaid-svg-14fuhXDnBjGvv8Qn .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-14fuhXDnBjGvv8Qn .rough-node .label,#mermaid-svg-14fuhXDnBjGvv8Qn .node .label,#mermaid-svg-14fuhXDnBjGvv8Qn .image-shape .label,#mermaid-svg-14fuhXDnBjGvv8Qn .icon-shape .label{text-align:center;}#mermaid-svg-14fuhXDnBjGvv8Qn .node.clickable{cursor:pointer;}#mermaid-svg-14fuhXDnBjGvv8Qn .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-14fuhXDnBjGvv8Qn .arrowheadPath{fill:#333333;}#mermaid-svg-14fuhXDnBjGvv8Qn .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-14fuhXDnBjGvv8Qn .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-14fuhXDnBjGvv8Qn .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-14fuhXDnBjGvv8Qn .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-14fuhXDnBjGvv8Qn .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-14fuhXDnBjGvv8Qn .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-14fuhXDnBjGvv8Qn .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-14fuhXDnBjGvv8Qn .cluster text{fill:#333;}#mermaid-svg-14fuhXDnBjGvv8Qn .cluster span{color:#333;}#mermaid-svg-14fuhXDnBjGvv8Qn div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-14fuhXDnBjGvv8Qn .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-14fuhXDnBjGvv8Qn rect.text{fill:none;stroke-width:0;}#mermaid-svg-14fuhXDnBjGvv8Qn .icon-shape,#mermaid-svg-14fuhXDnBjGvv8Qn .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-14fuhXDnBjGvv8Qn .icon-shape p,#mermaid-svg-14fuhXDnBjGvv8Qn .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-14fuhXDnBjGvv8Qn .icon-shape .label rect,#mermaid-svg-14fuhXDnBjGvv8Qn .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-14fuhXDnBjGvv8Qn .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-14fuhXDnBjGvv8Qn .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-14fuhXDnBjGvv8Qn :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} HomeTab
标题区
考研英语词汇 💪
今日进度卡片
渐变背景 + 动画进度条
统计网格
总词量/已掌握/熟悉/收藏
分类快捷入口
2x2 网格
今日推荐
随机 5 词 + 收藏按钮
核心交互:
- 点击分类卡片 → 切换到单词 Tab 并进入闪卡模式
- 点击收藏按钮 → 切换单词收藏状态
- 进度条动画 → Framer Motion
animate={``{ width }}
5.4 闪卡模式(FlashcardTab)
#mermaid-svg-kkk2fnWp8kLWsG9b{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-kkk2fnWp8kLWsG9b .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-kkk2fnWp8kLWsG9b .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-kkk2fnWp8kLWsG9b .error-icon{fill:#552222;}#mermaid-svg-kkk2fnWp8kLWsG9b .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-kkk2fnWp8kLWsG9b .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-kkk2fnWp8kLWsG9b .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-kkk2fnWp8kLWsG9b .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-kkk2fnWp8kLWsG9b .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-kkk2fnWp8kLWsG9b .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-kkk2fnWp8kLWsG9b .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-kkk2fnWp8kLWsG9b .marker{fill:#333333;stroke:#333333;}#mermaid-svg-kkk2fnWp8kLWsG9b .marker.cross{stroke:#333333;}#mermaid-svg-kkk2fnWp8kLWsG9b svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-kkk2fnWp8kLWsG9b p{margin:0;}#mermaid-svg-kkk2fnWp8kLWsG9b .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-kkk2fnWp8kLWsG9b .cluster-label text{fill:#333;}#mermaid-svg-kkk2fnWp8kLWsG9b .cluster-label span{color:#333;}#mermaid-svg-kkk2fnWp8kLWsG9b .cluster-label span p{background-color:transparent;}#mermaid-svg-kkk2fnWp8kLWsG9b .label text,#mermaid-svg-kkk2fnWp8kLWsG9b span{fill:#333;color:#333;}#mermaid-svg-kkk2fnWp8kLWsG9b .node rect,#mermaid-svg-kkk2fnWp8kLWsG9b .node circle,#mermaid-svg-kkk2fnWp8kLWsG9b .node ellipse,#mermaid-svg-kkk2fnWp8kLWsG9b .node polygon,#mermaid-svg-kkk2fnWp8kLWsG9b .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-kkk2fnWp8kLWsG9b .rough-node .label text,#mermaid-svg-kkk2fnWp8kLWsG9b .node .label text,#mermaid-svg-kkk2fnWp8kLWsG9b .image-shape .label,#mermaid-svg-kkk2fnWp8kLWsG9b .icon-shape .label{text-anchor:middle;}#mermaid-svg-kkk2fnWp8kLWsG9b .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-kkk2fnWp8kLWsG9b .rough-node .label,#mermaid-svg-kkk2fnWp8kLWsG9b .node .label,#mermaid-svg-kkk2fnWp8kLWsG9b .image-shape .label,#mermaid-svg-kkk2fnWp8kLWsG9b .icon-shape .label{text-align:center;}#mermaid-svg-kkk2fnWp8kLWsG9b .node.clickable{cursor:pointer;}#mermaid-svg-kkk2fnWp8kLWsG9b .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-kkk2fnWp8kLWsG9b .arrowheadPath{fill:#333333;}#mermaid-svg-kkk2fnWp8kLWsG9b .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-kkk2fnWp8kLWsG9b .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-kkk2fnWp8kLWsG9b .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kkk2fnWp8kLWsG9b .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-kkk2fnWp8kLWsG9b .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kkk2fnWp8kLWsG9b .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-kkk2fnWp8kLWsG9b .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-kkk2fnWp8kLWsG9b .cluster text{fill:#333;}#mermaid-svg-kkk2fnWp8kLWsG9b .cluster span{color:#333;}#mermaid-svg-kkk2fnWp8kLWsG9b div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-kkk2fnWp8kLWsG9b .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-kkk2fnWp8kLWsG9b rect.text{fill:none;stroke-width:0;}#mermaid-svg-kkk2fnWp8kLWsG9b .icon-shape,#mermaid-svg-kkk2fnWp8kLWsG9b .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kkk2fnWp8kLWsG9b .icon-shape p,#mermaid-svg-kkk2fnWp8kLWsG9b .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-kkk2fnWp8kLWsG9b .icon-shape .label rect,#mermaid-svg-kkk2fnWp8kLWsG9b .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kkk2fnWp8kLWsG9b .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-kkk2fnWp8kLWsG9b .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-kkk2fnWp8kLWsG9b :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} FlashcardTab
分类筛选栏
进度指示
Progress + 计数
卡片区域
控制区
FlashCard 组件
3D 翻转动画
正面
单词 + 音标 + 分类标签 + 考频
背面
释义 + 例句 + 记忆提示
掌握/熟悉 按钮
上一张 / 翻转 / 下一张
3D 翻转实现:
#mermaid-svg-yfSZRmoZndq77giy{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-yfSZRmoZndq77giy .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-yfSZRmoZndq77giy .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-yfSZRmoZndq77giy .error-icon{fill:#552222;}#mermaid-svg-yfSZRmoZndq77giy .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-yfSZRmoZndq77giy .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-yfSZRmoZndq77giy .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-yfSZRmoZndq77giy .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-yfSZRmoZndq77giy .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-yfSZRmoZndq77giy .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-yfSZRmoZndq77giy .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-yfSZRmoZndq77giy .marker{fill:#333333;stroke:#333333;}#mermaid-svg-yfSZRmoZndq77giy .marker.cross{stroke:#333333;}#mermaid-svg-yfSZRmoZndq77giy svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-yfSZRmoZndq77giy p{margin:0;}#mermaid-svg-yfSZRmoZndq77giy .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-yfSZRmoZndq77giy .cluster-label text{fill:#333;}#mermaid-svg-yfSZRmoZndq77giy .cluster-label span{color:#333;}#mermaid-svg-yfSZRmoZndq77giy .cluster-label span p{background-color:transparent;}#mermaid-svg-yfSZRmoZndq77giy .label text,#mermaid-svg-yfSZRmoZndq77giy span{fill:#333;color:#333;}#mermaid-svg-yfSZRmoZndq77giy .node rect,#mermaid-svg-yfSZRmoZndq77giy .node circle,#mermaid-svg-yfSZRmoZndq77giy .node ellipse,#mermaid-svg-yfSZRmoZndq77giy .node polygon,#mermaid-svg-yfSZRmoZndq77giy .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-yfSZRmoZndq77giy .rough-node .label text,#mermaid-svg-yfSZRmoZndq77giy .node .label text,#mermaid-svg-yfSZRmoZndq77giy .image-shape .label,#mermaid-svg-yfSZRmoZndq77giy .icon-shape .label{text-anchor:middle;}#mermaid-svg-yfSZRmoZndq77giy .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-yfSZRmoZndq77giy .rough-node .label,#mermaid-svg-yfSZRmoZndq77giy .node .label,#mermaid-svg-yfSZRmoZndq77giy .image-shape .label,#mermaid-svg-yfSZRmoZndq77giy .icon-shape .label{text-align:center;}#mermaid-svg-yfSZRmoZndq77giy .node.clickable{cursor:pointer;}#mermaid-svg-yfSZRmoZndq77giy .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-yfSZRmoZndq77giy .arrowheadPath{fill:#333333;}#mermaid-svg-yfSZRmoZndq77giy .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-yfSZRmoZndq77giy .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-yfSZRmoZndq77giy .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yfSZRmoZndq77giy .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-yfSZRmoZndq77giy .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yfSZRmoZndq77giy .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-yfSZRmoZndq77giy .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-yfSZRmoZndq77giy .cluster text{fill:#333;}#mermaid-svg-yfSZRmoZndq77giy .cluster span{color:#333;}#mermaid-svg-yfSZRmoZndq77giy div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-yfSZRmoZndq77giy .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-yfSZRmoZndq77giy rect.text{fill:none;stroke-width:0;}#mermaid-svg-yfSZRmoZndq77giy .icon-shape,#mermaid-svg-yfSZRmoZndq77giy .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yfSZRmoZndq77giy .icon-shape p,#mermaid-svg-yfSZRmoZndq77giy .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-yfSZRmoZndq77giy .icon-shape .label rect,#mermaid-svg-yfSZRmoZndq77giy .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yfSZRmoZndq77giy .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-yfSZRmoZndq77giy .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-yfSZRmoZndq77giy :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 用户点击卡片
触发 onFlip
Zustand: flipCard()
isFlipped = !isFlipped
Framer Motion
animate={{ rotateY: 180 }}
CSS: backface-visibility: hidden
卡片翻转展示背面
5.5 列表模式(WordListTab)
#mermaid-svg-WMCTEnOPRuzNsEsr{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-WMCTEnOPRuzNsEsr .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-WMCTEnOPRuzNsEsr .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-WMCTEnOPRuzNsEsr .error-icon{fill:#552222;}#mermaid-svg-WMCTEnOPRuzNsEsr .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-WMCTEnOPRuzNsEsr .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-WMCTEnOPRuzNsEsr .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-WMCTEnOPRuzNsEsr .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-WMCTEnOPRuzNsEsr .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-WMCTEnOPRuzNsEsr .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-WMCTEnOPRuzNsEsr .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-WMCTEnOPRuzNsEsr .marker{fill:#333333;stroke:#333333;}#mermaid-svg-WMCTEnOPRuzNsEsr .marker.cross{stroke:#333333;}#mermaid-svg-WMCTEnOPRuzNsEsr svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-WMCTEnOPRuzNsEsr p{margin:0;}#mermaid-svg-WMCTEnOPRuzNsEsr .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-WMCTEnOPRuzNsEsr .cluster-label text{fill:#333;}#mermaid-svg-WMCTEnOPRuzNsEsr .cluster-label span{color:#333;}#mermaid-svg-WMCTEnOPRuzNsEsr .cluster-label span p{background-color:transparent;}#mermaid-svg-WMCTEnOPRuzNsEsr .label text,#mermaid-svg-WMCTEnOPRuzNsEsr span{fill:#333;color:#333;}#mermaid-svg-WMCTEnOPRuzNsEsr .node rect,#mermaid-svg-WMCTEnOPRuzNsEsr .node circle,#mermaid-svg-WMCTEnOPRuzNsEsr .node ellipse,#mermaid-svg-WMCTEnOPRuzNsEsr .node polygon,#mermaid-svg-WMCTEnOPRuzNsEsr .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-WMCTEnOPRuzNsEsr .rough-node .label text,#mermaid-svg-WMCTEnOPRuzNsEsr .node .label text,#mermaid-svg-WMCTEnOPRuzNsEsr .image-shape .label,#mermaid-svg-WMCTEnOPRuzNsEsr .icon-shape .label{text-anchor:middle;}#mermaid-svg-WMCTEnOPRuzNsEsr .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-WMCTEnOPRuzNsEsr .rough-node .label,#mermaid-svg-WMCTEnOPRuzNsEsr .node .label,#mermaid-svg-WMCTEnOPRuzNsEsr .image-shape .label,#mermaid-svg-WMCTEnOPRuzNsEsr .icon-shape .label{text-align:center;}#mermaid-svg-WMCTEnOPRuzNsEsr .node.clickable{cursor:pointer;}#mermaid-svg-WMCTEnOPRuzNsEsr .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-WMCTEnOPRuzNsEsr .arrowheadPath{fill:#333333;}#mermaid-svg-WMCTEnOPRuzNsEsr .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-WMCTEnOPRuzNsEsr .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-WMCTEnOPRuzNsEsr .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WMCTEnOPRuzNsEsr .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-WMCTEnOPRuzNsEsr .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WMCTEnOPRuzNsEsr .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-WMCTEnOPRuzNsEsr .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-WMCTEnOPRuzNsEsr .cluster text{fill:#333;}#mermaid-svg-WMCTEnOPRuzNsEsr .cluster span{color:#333;}#mermaid-svg-WMCTEnOPRuzNsEsr div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-WMCTEnOPRuzNsEsr .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-WMCTEnOPRuzNsEsr rect.text{fill:none;stroke-width:0;}#mermaid-svg-WMCTEnOPRuzNsEsr .icon-shape,#mermaid-svg-WMCTEnOPRuzNsEsr .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WMCTEnOPRuzNsEsr .icon-shape p,#mermaid-svg-WMCTEnOPRuzNsEsr .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-WMCTEnOPRuzNsEsr .icon-shape .label rect,#mermaid-svg-WMCTEnOPRuzNsEsr .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WMCTEnOPRuzNsEsr .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-WMCTEnOPRuzNsEsr .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-WMCTEnOPRuzNsEsr :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} WordListTab
搜索栏
单词/释义/标签
收藏筛选
分类标签栏
横向滚动
单词列表
ScrollArea 虚拟滚动
单词条目
单词 + 音标 + 状态标签
核心释义
掌握/熟悉按钮 + 分类标签
收藏按钮
性能优化:
- 分页加载:初始显示 50 词,点击"加载更多"增量加载
useMemo缓存过滤结果ScrollArea优化长列表滚动性能
5.6 测验模式(QuizMode)
#mermaid-svg-CvqqVTuxDFbjqxv6{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-CvqqVTuxDFbjqxv6 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-CvqqVTuxDFbjqxv6 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-CvqqVTuxDFbjqxv6 .error-icon{fill:#552222;}#mermaid-svg-CvqqVTuxDFbjqxv6 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-CvqqVTuxDFbjqxv6 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-CvqqVTuxDFbjqxv6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-CvqqVTuxDFbjqxv6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-CvqqVTuxDFbjqxv6 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-CvqqVTuxDFbjqxv6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-CvqqVTuxDFbjqxv6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-CvqqVTuxDFbjqxv6 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-CvqqVTuxDFbjqxv6 .marker.cross{stroke:#333333;}#mermaid-svg-CvqqVTuxDFbjqxv6 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-CvqqVTuxDFbjqxv6 p{margin:0;}#mermaid-svg-CvqqVTuxDFbjqxv6 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-CvqqVTuxDFbjqxv6 .cluster-label text{fill:#333;}#mermaid-svg-CvqqVTuxDFbjqxv6 .cluster-label span{color:#333;}#mermaid-svg-CvqqVTuxDFbjqxv6 .cluster-label span p{background-color:transparent;}#mermaid-svg-CvqqVTuxDFbjqxv6 .label text,#mermaid-svg-CvqqVTuxDFbjqxv6 span{fill:#333;color:#333;}#mermaid-svg-CvqqVTuxDFbjqxv6 .node rect,#mermaid-svg-CvqqVTuxDFbjqxv6 .node circle,#mermaid-svg-CvqqVTuxDFbjqxv6 .node ellipse,#mermaid-svg-CvqqVTuxDFbjqxv6 .node polygon,#mermaid-svg-CvqqVTuxDFbjqxv6 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-CvqqVTuxDFbjqxv6 .rough-node .label text,#mermaid-svg-CvqqVTuxDFbjqxv6 .node .label text,#mermaid-svg-CvqqVTuxDFbjqxv6 .image-shape .label,#mermaid-svg-CvqqVTuxDFbjqxv6 .icon-shape .label{text-anchor:middle;}#mermaid-svg-CvqqVTuxDFbjqxv6 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-CvqqVTuxDFbjqxv6 .rough-node .label,#mermaid-svg-CvqqVTuxDFbjqxv6 .node .label,#mermaid-svg-CvqqVTuxDFbjqxv6 .image-shape .label,#mermaid-svg-CvqqVTuxDFbjqxv6 .icon-shape .label{text-align:center;}#mermaid-svg-CvqqVTuxDFbjqxv6 .node.clickable{cursor:pointer;}#mermaid-svg-CvqqVTuxDFbjqxv6 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-CvqqVTuxDFbjqxv6 .arrowheadPath{fill:#333333;}#mermaid-svg-CvqqVTuxDFbjqxv6 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-CvqqVTuxDFbjqxv6 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-CvqqVTuxDFbjqxv6 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CvqqVTuxDFbjqxv6 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-CvqqVTuxDFbjqxv6 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CvqqVTuxDFbjqxv6 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-CvqqVTuxDFbjqxv6 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-CvqqVTuxDFbjqxv6 .cluster text{fill:#333;}#mermaid-svg-CvqqVTuxDFbjqxv6 .cluster span{color:#333;}#mermaid-svg-CvqqVTuxDFbjqxv6 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-CvqqVTuxDFbjqxv6 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-CvqqVTuxDFbjqxv6 rect.text{fill:none;stroke-width:0;}#mermaid-svg-CvqqVTuxDFbjqxv6 .icon-shape,#mermaid-svg-CvqqVTuxDFbjqxv6 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CvqqVTuxDFbjqxv6 .icon-shape p,#mermaid-svg-CvqqVTuxDFbjqxv6 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-CvqqVTuxDFbjqxv6 .icon-shape .label rect,#mermaid-svg-CvqqVTuxDFbjqxv6 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CvqqVTuxDFbjqxv6 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-CvqqVTuxDFbjqxv6 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-CvqqVTuxDFbjqxv6 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 最后一题
QuizMode
题目生成
随机 20 题
当前题目
单词卡片
单词 + 音标
四个选项
1 正确 + 3 干扰项
用户选择
正确
绿色高亮 + 记忆提示
错误
红色高亮 + 显示正确答案
下一题
结果页
得分 + 正确率 + 评价
干扰项生成算法:
- 从当前分类中随机选取 3 个不同单词
- 与正确答案一起随机排序
- 每轮测验重新生成(通过
quizKey触发useMemo重新计算)
5.7 个人中心(ProfileTab)
#mermaid-svg-1opQytN0aQDruZqH{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-1opQytN0aQDruZqH .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-1opQytN0aQDruZqH .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-1opQytN0aQDruZqH .error-icon{fill:#552222;}#mermaid-svg-1opQytN0aQDruZqH .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-1opQytN0aQDruZqH .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-1opQytN0aQDruZqH .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-1opQytN0aQDruZqH .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-1opQytN0aQDruZqH .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-1opQytN0aQDruZqH .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-1opQytN0aQDruZqH .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-1opQytN0aQDruZqH .marker{fill:#333333;stroke:#333333;}#mermaid-svg-1opQytN0aQDruZqH .marker.cross{stroke:#333333;}#mermaid-svg-1opQytN0aQDruZqH svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-1opQytN0aQDruZqH p{margin:0;}#mermaid-svg-1opQytN0aQDruZqH .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-1opQytN0aQDruZqH .cluster-label text{fill:#333;}#mermaid-svg-1opQytN0aQDruZqH .cluster-label span{color:#333;}#mermaid-svg-1opQytN0aQDruZqH .cluster-label span p{background-color:transparent;}#mermaid-svg-1opQytN0aQDruZqH .label text,#mermaid-svg-1opQytN0aQDruZqH span{fill:#333;color:#333;}#mermaid-svg-1opQytN0aQDruZqH .node rect,#mermaid-svg-1opQytN0aQDruZqH .node circle,#mermaid-svg-1opQytN0aQDruZqH .node ellipse,#mermaid-svg-1opQytN0aQDruZqH .node polygon,#mermaid-svg-1opQytN0aQDruZqH .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-1opQytN0aQDruZqH .rough-node .label text,#mermaid-svg-1opQytN0aQDruZqH .node .label text,#mermaid-svg-1opQytN0aQDruZqH .image-shape .label,#mermaid-svg-1opQytN0aQDruZqH .icon-shape .label{text-anchor:middle;}#mermaid-svg-1opQytN0aQDruZqH .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-1opQytN0aQDruZqH .rough-node .label,#mermaid-svg-1opQytN0aQDruZqH .node .label,#mermaid-svg-1opQytN0aQDruZqH .image-shape .label,#mermaid-svg-1opQytN0aQDruZqH .icon-shape .label{text-align:center;}#mermaid-svg-1opQytN0aQDruZqH .node.clickable{cursor:pointer;}#mermaid-svg-1opQytN0aQDruZqH .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-1opQytN0aQDruZqH .arrowheadPath{fill:#333333;}#mermaid-svg-1opQytN0aQDruZqH .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-1opQytN0aQDruZqH .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-1opQytN0aQDruZqH .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1opQytN0aQDruZqH .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-1opQytN0aQDruZqH .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1opQytN0aQDruZqH .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-1opQytN0aQDruZqH .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-1opQytN0aQDruZqH .cluster text{fill:#333;}#mermaid-svg-1opQytN0aQDruZqH .cluster span{color:#333;}#mermaid-svg-1opQytN0aQDruZqH div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-1opQytN0aQDruZqH .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-1opQytN0aQDruZqH rect.text{fill:none;stroke-width:0;}#mermaid-svg-1opQytN0aQDruZqH .icon-shape,#mermaid-svg-1opQytN0aQDruZqH .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1opQytN0aQDruZqH .icon-shape p,#mermaid-svg-1opQytN0aQDruZqH .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-1opQytN0aQDruZqH .icon-shape .label rect,#mermaid-svg-1opQytN0aQDruZqH .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1opQytN0aQDruZqH .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-1opQytN0aQDruZqH .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-1opQytN0aQDruZqH :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ProfileTab
头像区
考研战士
总体进度
已掌握百分比 + 三列统计
分类进度
各分类掌握情况条形图
学习统计
今日已学/目标/收藏
每日目标设置
20/30/50/80/100
重置进度
6. 数据流设计
6.1 词汇数据流
#mermaid-svg-hvqBJvL2LJ4lLQEk{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-hvqBJvL2LJ4lLQEk .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-hvqBJvL2LJ4lLQEk .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-hvqBJvL2LJ4lLQEk .error-icon{fill:#552222;}#mermaid-svg-hvqBJvL2LJ4lLQEk .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-hvqBJvL2LJ4lLQEk .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-hvqBJvL2LJ4lLQEk .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-hvqBJvL2LJ4lLQEk .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-hvqBJvL2LJ4lLQEk .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-hvqBJvL2LJ4lLQEk .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-hvqBJvL2LJ4lLQEk .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-hvqBJvL2LJ4lLQEk .marker{fill:#333333;stroke:#333333;}#mermaid-svg-hvqBJvL2LJ4lLQEk .marker.cross{stroke:#333333;}#mermaid-svg-hvqBJvL2LJ4lLQEk svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-hvqBJvL2LJ4lLQEk p{margin:0;}#mermaid-svg-hvqBJvL2LJ4lLQEk .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-hvqBJvL2LJ4lLQEk .cluster-label text{fill:#333;}#mermaid-svg-hvqBJvL2LJ4lLQEk .cluster-label span{color:#333;}#mermaid-svg-hvqBJvL2LJ4lLQEk .cluster-label span p{background-color:transparent;}#mermaid-svg-hvqBJvL2LJ4lLQEk .label text,#mermaid-svg-hvqBJvL2LJ4lLQEk span{fill:#333;color:#333;}#mermaid-svg-hvqBJvL2LJ4lLQEk .node rect,#mermaid-svg-hvqBJvL2LJ4lLQEk .node circle,#mermaid-svg-hvqBJvL2LJ4lLQEk .node ellipse,#mermaid-svg-hvqBJvL2LJ4lLQEk .node polygon,#mermaid-svg-hvqBJvL2LJ4lLQEk .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-hvqBJvL2LJ4lLQEk .rough-node .label text,#mermaid-svg-hvqBJvL2LJ4lLQEk .node .label text,#mermaid-svg-hvqBJvL2LJ4lLQEk .image-shape .label,#mermaid-svg-hvqBJvL2LJ4lLQEk .icon-shape .label{text-anchor:middle;}#mermaid-svg-hvqBJvL2LJ4lLQEk .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-hvqBJvL2LJ4lLQEk .rough-node .label,#mermaid-svg-hvqBJvL2LJ4lLQEk .node .label,#mermaid-svg-hvqBJvL2LJ4lLQEk .image-shape .label,#mermaid-svg-hvqBJvL2LJ4lLQEk .icon-shape .label{text-align:center;}#mermaid-svg-hvqBJvL2LJ4lLQEk .node.clickable{cursor:pointer;}#mermaid-svg-hvqBJvL2LJ4lLQEk .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-hvqBJvL2LJ4lLQEk .arrowheadPath{fill:#333333;}#mermaid-svg-hvqBJvL2LJ4lLQEk .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-hvqBJvL2LJ4lLQEk .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-hvqBJvL2LJ4lLQEk .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hvqBJvL2LJ4lLQEk .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-hvqBJvL2LJ4lLQEk .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hvqBJvL2LJ4lLQEk .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-hvqBJvL2LJ4lLQEk .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-hvqBJvL2LJ4lLQEk .cluster text{fill:#333;}#mermaid-svg-hvqBJvL2LJ4lLQEk .cluster span{color:#333;}#mermaid-svg-hvqBJvL2LJ4lLQEk div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-hvqBJvL2LJ4lLQEk .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-hvqBJvL2LJ4lLQEk rect.text{fill:none;stroke-width:0;}#mermaid-svg-hvqBJvL2LJ4lLQEk .icon-shape,#mermaid-svg-hvqBJvL2LJ4lLQEk .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hvqBJvL2LJ4lLQEk .icon-shape p,#mermaid-svg-hvqBJvL2LJ4lLQEk .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-hvqBJvL2LJ4lLQEk .icon-shape .label rect,#mermaid-svg-hvqBJvL2LJ4lLQEk .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hvqBJvL2LJ4lLQEk .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-hvqBJvL2LJ4lLQEk .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-hvqBJvL2LJ4lLQEk :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 14 个数据源
vocabulary.ts
vocab-core-*.ts
vocab-ac ~ tz.ts
vocab-supplement*.ts
index.ts
合并 + 去重 + 分类分配
allVocabulary\[\]
~5500+ 词
page.tsx
Zustand Store
各 Tab 组件
6.2 状态数据流
#mermaid-svg-m8oxCbQNiKg7St2W{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-m8oxCbQNiKg7St2W .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-m8oxCbQNiKg7St2W .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-m8oxCbQNiKg7St2W .error-icon{fill:#552222;}#mermaid-svg-m8oxCbQNiKg7St2W .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-m8oxCbQNiKg7St2W .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-m8oxCbQNiKg7St2W .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-m8oxCbQNiKg7St2W .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-m8oxCbQNiKg7St2W .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-m8oxCbQNiKg7St2W .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-m8oxCbQNiKg7St2W .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-m8oxCbQNiKg7St2W .marker{fill:#333333;stroke:#333333;}#mermaid-svg-m8oxCbQNiKg7St2W .marker.cross{stroke:#333333;}#mermaid-svg-m8oxCbQNiKg7St2W svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-m8oxCbQNiKg7St2W p{margin:0;}#mermaid-svg-m8oxCbQNiKg7St2W .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-m8oxCbQNiKg7St2W .cluster-label text{fill:#333;}#mermaid-svg-m8oxCbQNiKg7St2W .cluster-label span{color:#333;}#mermaid-svg-m8oxCbQNiKg7St2W .cluster-label span p{background-color:transparent;}#mermaid-svg-m8oxCbQNiKg7St2W .label text,#mermaid-svg-m8oxCbQNiKg7St2W span{fill:#333;color:#333;}#mermaid-svg-m8oxCbQNiKg7St2W .node rect,#mermaid-svg-m8oxCbQNiKg7St2W .node circle,#mermaid-svg-m8oxCbQNiKg7St2W .node ellipse,#mermaid-svg-m8oxCbQNiKg7St2W .node polygon,#mermaid-svg-m8oxCbQNiKg7St2W .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-m8oxCbQNiKg7St2W .rough-node .label text,#mermaid-svg-m8oxCbQNiKg7St2W .node .label text,#mermaid-svg-m8oxCbQNiKg7St2W .image-shape .label,#mermaid-svg-m8oxCbQNiKg7St2W .icon-shape .label{text-anchor:middle;}#mermaid-svg-m8oxCbQNiKg7St2W .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-m8oxCbQNiKg7St2W .rough-node .label,#mermaid-svg-m8oxCbQNiKg7St2W .node .label,#mermaid-svg-m8oxCbQNiKg7St2W .image-shape .label,#mermaid-svg-m8oxCbQNiKg7St2W .icon-shape .label{text-align:center;}#mermaid-svg-m8oxCbQNiKg7St2W .node.clickable{cursor:pointer;}#mermaid-svg-m8oxCbQNiKg7St2W .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-m8oxCbQNiKg7St2W .arrowheadPath{fill:#333333;}#mermaid-svg-m8oxCbQNiKg7St2W .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-m8oxCbQNiKg7St2W .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-m8oxCbQNiKg7St2W .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-m8oxCbQNiKg7St2W .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-m8oxCbQNiKg7St2W .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-m8oxCbQNiKg7St2W .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-m8oxCbQNiKg7St2W .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-m8oxCbQNiKg7St2W .cluster text{fill:#333;}#mermaid-svg-m8oxCbQNiKg7St2W .cluster span{color:#333;}#mermaid-svg-m8oxCbQNiKg7St2W div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-m8oxCbQNiKg7St2W .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-m8oxCbQNiKg7St2W rect.text{fill:none;stroke-width:0;}#mermaid-svg-m8oxCbQNiKg7St2W .icon-shape,#mermaid-svg-m8oxCbQNiKg7St2W .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-m8oxCbQNiKg7St2W .icon-shape p,#mermaid-svg-m8oxCbQNiKg7St2W .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-m8oxCbQNiKg7St2W .icon-shape .label rect,#mermaid-svg-m8oxCbQNiKg7St2W .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-m8oxCbQNiKg7St2W .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-m8oxCbQNiKg7St2W .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-m8oxCbQNiKg7St2W :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 全局状态 (Zustand)
currentCategory
currentWordIndex
isFlipped
masteredWords\[\]
familiarWords\[\]
bookmarkedWords\[\]
quizState
searchQuery
dailyGoal / dailyLearned
vocab-store.ts
HomeTab
FlashcardTab
WordListTab
QuizMode
ProfileTab
7. 核心算法与逻辑
7.1 数据去重与合并
#mermaid-svg-QkMz5Ci5XbVODOjQ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-QkMz5Ci5XbVODOjQ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-QkMz5Ci5XbVODOjQ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-QkMz5Ci5XbVODOjQ .error-icon{fill:#552222;}#mermaid-svg-QkMz5Ci5XbVODOjQ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-QkMz5Ci5XbVODOjQ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-QkMz5Ci5XbVODOjQ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-QkMz5Ci5XbVODOjQ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-QkMz5Ci5XbVODOjQ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-QkMz5Ci5XbVODOjQ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-QkMz5Ci5XbVODOjQ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-QkMz5Ci5XbVODOjQ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-QkMz5Ci5XbVODOjQ .marker.cross{stroke:#333333;}#mermaid-svg-QkMz5Ci5XbVODOjQ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-QkMz5Ci5XbVODOjQ p{margin:0;}#mermaid-svg-QkMz5Ci5XbVODOjQ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-QkMz5Ci5XbVODOjQ .cluster-label text{fill:#333;}#mermaid-svg-QkMz5Ci5XbVODOjQ .cluster-label span{color:#333;}#mermaid-svg-QkMz5Ci5XbVODOjQ .cluster-label span p{background-color:transparent;}#mermaid-svg-QkMz5Ci5XbVODOjQ .label text,#mermaid-svg-QkMz5Ci5XbVODOjQ span{fill:#333;color:#333;}#mermaid-svg-QkMz5Ci5XbVODOjQ .node rect,#mermaid-svg-QkMz5Ci5XbVODOjQ .node circle,#mermaid-svg-QkMz5Ci5XbVODOjQ .node ellipse,#mermaid-svg-QkMz5Ci5XbVODOjQ .node polygon,#mermaid-svg-QkMz5Ci5XbVODOjQ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-QkMz5Ci5XbVODOjQ .rough-node .label text,#mermaid-svg-QkMz5Ci5XbVODOjQ .node .label text,#mermaid-svg-QkMz5Ci5XbVODOjQ .image-shape .label,#mermaid-svg-QkMz5Ci5XbVODOjQ .icon-shape .label{text-anchor:middle;}#mermaid-svg-QkMz5Ci5XbVODOjQ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-QkMz5Ci5XbVODOjQ .rough-node .label,#mermaid-svg-QkMz5Ci5XbVODOjQ .node .label,#mermaid-svg-QkMz5Ci5XbVODOjQ .image-shape .label,#mermaid-svg-QkMz5Ci5XbVODOjQ .icon-shape .label{text-align:center;}#mermaid-svg-QkMz5Ci5XbVODOjQ .node.clickable{cursor:pointer;}#mermaid-svg-QkMz5Ci5XbVODOjQ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-QkMz5Ci5XbVODOjQ .arrowheadPath{fill:#333333;}#mermaid-svg-QkMz5Ci5XbVODOjQ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-QkMz5Ci5XbVODOjQ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-QkMz5Ci5XbVODOjQ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-QkMz5Ci5XbVODOjQ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-QkMz5Ci5XbVODOjQ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-QkMz5Ci5XbVODOjQ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-QkMz5Ci5XbVODOjQ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-QkMz5Ci5XbVODOjQ .cluster text{fill:#333;}#mermaid-svg-QkMz5Ci5XbVODOjQ .cluster span{color:#333;}#mermaid-svg-QkMz5Ci5XbVODOjQ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-QkMz5Ci5XbVODOjQ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-QkMz5Ci5XbVODOjQ rect.text{fill:none;stroke-width:0;}#mermaid-svg-QkMz5Ci5XbVODOjQ .icon-shape,#mermaid-svg-QkMz5Ci5XbVODOjQ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-QkMz5Ci5XbVODOjQ .icon-shape p,#mermaid-svg-QkMz5Ci5XbVODOjQ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-QkMz5Ci5XbVODOjQ .icon-shape .label rect,#mermaid-svg-QkMz5Ci5XbVODOjQ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-QkMz5Ci5XbVODOjQ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-QkMz5Ci5XbVODOjQ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-QkMz5Ci5XbVODOjQ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} No
Yes
14 个词汇源数组
按优先级排序
遍历所有单词
seen.has
word.toLowerCase()?
存入 seen Map
跳过(保留更详细的版本)
分配顺序 ID: w1, w2, ...
assignCategories
自动多分类分配
allVocabulary\[\]
优先级规则:
vocabulary.ts(最详细,含例句和记忆提示)vocab-core-*.ts(核心词扩展)vocab-ac.ts~vocab-tz.ts(按字母分区)vocab-supplement*.ts(补充词汇)
7.2 自动分类分配算法
基于单词的 category、frequency、tags 自动分配多分类标签:
| 条件 | 分配分类 |
|---|---|
core + freq >= 5 |
reading, writing |
core + freq >= 4 + 动词/名词/高频 |
reading |
core + 标签含 易混/辨析/多义/用法 |
cloze |
core + 标签含 搭配/写作/虚拟语气 |
writing |
core + freq >= 4 + 形容词 |
reading, writing |
basic + freq >= 4 |
reading |
reading + freq >= 4 |
writing |
writing |
reading |
cloze + freq >= 4 |
reading |
7.3 测验干扰项生成
#mermaid-svg-fh2V5NQXRuXGbbnC{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-fh2V5NQXRuXGbbnC .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-fh2V5NQXRuXGbbnC .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-fh2V5NQXRuXGbbnC .error-icon{fill:#552222;}#mermaid-svg-fh2V5NQXRuXGbbnC .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-fh2V5NQXRuXGbbnC .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-fh2V5NQXRuXGbbnC .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-fh2V5NQXRuXGbbnC .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-fh2V5NQXRuXGbbnC .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-fh2V5NQXRuXGbbnC .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-fh2V5NQXRuXGbbnC .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-fh2V5NQXRuXGbbnC .marker{fill:#333333;stroke:#333333;}#mermaid-svg-fh2V5NQXRuXGbbnC .marker.cross{stroke:#333333;}#mermaid-svg-fh2V5NQXRuXGbbnC svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-fh2V5NQXRuXGbbnC p{margin:0;}#mermaid-svg-fh2V5NQXRuXGbbnC .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-fh2V5NQXRuXGbbnC .cluster-label text{fill:#333;}#mermaid-svg-fh2V5NQXRuXGbbnC .cluster-label span{color:#333;}#mermaid-svg-fh2V5NQXRuXGbbnC .cluster-label span p{background-color:transparent;}#mermaid-svg-fh2V5NQXRuXGbbnC .label text,#mermaid-svg-fh2V5NQXRuXGbbnC span{fill:#333;color:#333;}#mermaid-svg-fh2V5NQXRuXGbbnC .node rect,#mermaid-svg-fh2V5NQXRuXGbbnC .node circle,#mermaid-svg-fh2V5NQXRuXGbbnC .node ellipse,#mermaid-svg-fh2V5NQXRuXGbbnC .node polygon,#mermaid-svg-fh2V5NQXRuXGbbnC .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-fh2V5NQXRuXGbbnC .rough-node .label text,#mermaid-svg-fh2V5NQXRuXGbbnC .node .label text,#mermaid-svg-fh2V5NQXRuXGbbnC .image-shape .label,#mermaid-svg-fh2V5NQXRuXGbbnC .icon-shape .label{text-anchor:middle;}#mermaid-svg-fh2V5NQXRuXGbbnC .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-fh2V5NQXRuXGbbnC .rough-node .label,#mermaid-svg-fh2V5NQXRuXGbbnC .node .label,#mermaid-svg-fh2V5NQXRuXGbbnC .image-shape .label,#mermaid-svg-fh2V5NQXRuXGbbnC .icon-shape .label{text-align:center;}#mermaid-svg-fh2V5NQXRuXGbbnC .node.clickable{cursor:pointer;}#mermaid-svg-fh2V5NQXRuXGbbnC .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-fh2V5NQXRuXGbbnC .arrowheadPath{fill:#333333;}#mermaid-svg-fh2V5NQXRuXGbbnC .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-fh2V5NQXRuXGbbnC .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-fh2V5NQXRuXGbbnC .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-fh2V5NQXRuXGbbnC .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-fh2V5NQXRuXGbbnC .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-fh2V5NQXRuXGbbnC .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-fh2V5NQXRuXGbbnC .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-fh2V5NQXRuXGbbnC .cluster text{fill:#333;}#mermaid-svg-fh2V5NQXRuXGbbnC .cluster span{color:#333;}#mermaid-svg-fh2V5NQXRuXGbbnC div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-fh2V5NQXRuXGbbnC .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-fh2V5NQXRuXGbbnC rect.text{fill:none;stroke-width:0;}#mermaid-svg-fh2V5NQXRuXGbbnC .icon-shape,#mermaid-svg-fh2V5NQXRuXGbbnC .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-fh2V5NQXRuXGbbnC .icon-shape p,#mermaid-svg-fh2V5NQXRuXGbbnC .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-fh2V5NQXRuXGbbnC .icon-shape .label rect,#mermaid-svg-fh2V5NQXRuXGbbnC .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-fh2V5NQXRuXGbbnC .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-fh2V5NQXRuXGbbnC .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-fh2V5NQXRuXGbbnC :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 选取当前分类单词
随机打乱 shuffleArray
取前 20 个作为题目
每题生成选项
从全部分类单词中
过滤掉当前单词
随机选 3 个错误选项
与正确答案合并
再次随机排序
8. 样式与主题设计
8.1 色彩系统
| 用途 | 颜色值 | 说明 |
|---|---|---|
| 主色(微信绿) | #07C160 |
品牌主色,用于按钮、进度条、选中状态 |
| 主色深 | #06AD56 |
渐变深色端 |
| 主色浅 | #E8F8EE |
背景、浅色卡片 |
| 核心词 | #F59E0B |
琥珀色 |
| 阅读高频 | #8B5CF6 |
紫色 |
| 完形高频 | #EC4899 |
粉色 |
| 写作加分 | #06B6D4 |
青色 |
| 基础词 | #6B7280 |
灰色 |
8.2 布局规范
- 最大宽度 :
max-w-lg mx-auto(移动端优先,桌面端居中) - 底部安全区 :
pb-[max(0.25rem,env(safe-area-inset-bottom))] - 卡片圆角 :
rounded-2xl/rounded-xl - 按钮圆角 :
rounded-full - 间距系统:基于 Tailwind 默认间距
9. 构建与部署
9.1 构建配置
typescript
// next.config.ts
const nextConfig: NextConfig = {
output: "standalone", // 独立输出,适合容器化部署
typescript: {
ignoreBuildErrors: true, // 忽略 TS 错误(快速构建)
},
reactStrictMode: false,
};
9.2 构建流程
#mermaid-svg-uLOqiofrVnev1gPd{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-uLOqiofrVnev1gPd .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-uLOqiofrVnev1gPd .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-uLOqiofrVnev1gPd .error-icon{fill:#552222;}#mermaid-svg-uLOqiofrVnev1gPd .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-uLOqiofrVnev1gPd .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-uLOqiofrVnev1gPd .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-uLOqiofrVnev1gPd .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-uLOqiofrVnev1gPd .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-uLOqiofrVnev1gPd .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-uLOqiofrVnev1gPd .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-uLOqiofrVnev1gPd .marker{fill:#333333;stroke:#333333;}#mermaid-svg-uLOqiofrVnev1gPd .marker.cross{stroke:#333333;}#mermaid-svg-uLOqiofrVnev1gPd svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-uLOqiofrVnev1gPd p{margin:0;}#mermaid-svg-uLOqiofrVnev1gPd .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-uLOqiofrVnev1gPd .cluster-label text{fill:#333;}#mermaid-svg-uLOqiofrVnev1gPd .cluster-label span{color:#333;}#mermaid-svg-uLOqiofrVnev1gPd .cluster-label span p{background-color:transparent;}#mermaid-svg-uLOqiofrVnev1gPd .label text,#mermaid-svg-uLOqiofrVnev1gPd span{fill:#333;color:#333;}#mermaid-svg-uLOqiofrVnev1gPd .node rect,#mermaid-svg-uLOqiofrVnev1gPd .node circle,#mermaid-svg-uLOqiofrVnev1gPd .node ellipse,#mermaid-svg-uLOqiofrVnev1gPd .node polygon,#mermaid-svg-uLOqiofrVnev1gPd .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-uLOqiofrVnev1gPd .rough-node .label text,#mermaid-svg-uLOqiofrVnev1gPd .node .label text,#mermaid-svg-uLOqiofrVnev1gPd .image-shape .label,#mermaid-svg-uLOqiofrVnev1gPd .icon-shape .label{text-anchor:middle;}#mermaid-svg-uLOqiofrVnev1gPd .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-uLOqiofrVnev1gPd .rough-node .label,#mermaid-svg-uLOqiofrVnev1gPd .node .label,#mermaid-svg-uLOqiofrVnev1gPd .image-shape .label,#mermaid-svg-uLOqiofrVnev1gPd .icon-shape .label{text-align:center;}#mermaid-svg-uLOqiofrVnev1gPd .node.clickable{cursor:pointer;}#mermaid-svg-uLOqiofrVnev1gPd .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-uLOqiofrVnev1gPd .arrowheadPath{fill:#333333;}#mermaid-svg-uLOqiofrVnev1gPd .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-uLOqiofrVnev1gPd .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-uLOqiofrVnev1gPd .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-uLOqiofrVnev1gPd .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-uLOqiofrVnev1gPd .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-uLOqiofrVnev1gPd .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-uLOqiofrVnev1gPd .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-uLOqiofrVnev1gPd .cluster text{fill:#333;}#mermaid-svg-uLOqiofrVnev1gPd .cluster span{color:#333;}#mermaid-svg-uLOqiofrVnev1gPd div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-uLOqiofrVnev1gPd .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-uLOqiofrVnev1gPd rect.text{fill:none;stroke-width:0;}#mermaid-svg-uLOqiofrVnev1gPd .icon-shape,#mermaid-svg-uLOqiofrVnev1gPd .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-uLOqiofrVnev1gPd .icon-shape p,#mermaid-svg-uLOqiofrVnev1gPd .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-uLOqiofrVnev1gPd .icon-shape .label rect,#mermaid-svg-uLOqiofrVnev1gPd .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-uLOqiofrVnev1gPd .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-uLOqiofrVnev1gPd .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-uLOqiofrVnev1gPd :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} bun install
next build
生成 .next/standalone
复制 static 到 standalone
复制 public 到 standalone
bun .next/standalone/server.js
9.3 部署方式
| 方式 | 说明 |
|---|---|
| Standalone | 输出独立 Node.js 应用,无需依赖 node_modules |
| Caddy | 通过 Caddyfile 配置反向代理 |
| Docker | 可基于 node:alpine 或 oven/bun 镜像构建 |
10. 待优化与扩展点
10.1 当前局限性
- API 未使用 :
src/app/api/route.ts仅为占位,Prisma/SQLite 未深度集成 - 无后端同步:学习进度仅保存在 localStorage,无法跨设备同步
- 无用户系统 :
next-auth已安装但未配置,无登录/注册功能 - 数据体积大:所有词汇数据打包在 JS 中,首屏加载较重
- 无服务端渲染 :
page.tsx标记"use client",丧失 SSR 优势
10.2 建议扩展方向
| 方向 | 实现思路 |
|---|---|
| 后端 API | 将词汇数据迁移到数据库,通过 API 分页获取 |
| 用户系统 | 配置 next-auth,支持 OAuth 登录,同步学习进度 |
| 数据懒加载 | 按分类/字母分区动态导入词汇数据 |
| 复习算法 | 引入艾宾浩斯遗忘曲线,智能推荐复习单词 |
| 语音播放 | 集成 Web Speech API 或第三方 TTS 服务 |
| 暗黑模式 | 利用 next-themes 实现主题切换(已安装) |
| 国际化 | 利用 next-intl 支持多语言(已安装) |
11. 附录
11.1 词汇数据统计
| 数据文件 | 行数 | 说明 |
|---|---|---|
vocabulary.ts |
1704 | 核心词汇(最详细) |
vocab-io.ts |
1067 | I-O 分区词汇 |
vocab-ps.ts |
853 | P-S 分区词汇 |
vocab-dh.ts |
735 | D-H 分区词汇 |
vocab-ac.ts |
720 | A-C 分区词汇 |
vocab-tz.ts |
725 | T-Z 分区词汇 |
vocab-rcw.ts |
623 | 额外补充 |
vocab-supplement-al.ts |
535 | A-L 补充 |
vocab-core-ae.ts |
376 | 核心词 A-E |
vocab-core-fn.ts |
365 | 核心词 F-N |
vocab-core-oz.ts |
405 | 核心词 O-Z |
vocab-core-expanded.ts |
328 | 核心词扩展 |
vocab-extra.ts |
400 | 额外词汇 |
vocab-supplement-mz.ts |
286 | M-Z 补充 |
vocab-final-supplement.ts |
93 | 最终补充 |
| 总计 | ~9387 行 | ~5500+ 去重词汇 |
11.2 依赖版本锁定
关键生产依赖版本:
next: ^16.1.1react: ^19.0.0tailwindcss: ^4zustand: ^5.0.6framer-motion: ^12.23.2@prisma/client: ^6.11.1