简介这是一套基于Java开发的在线英语词汇量测试系统源码面向Java初学者与毕业设计学生解决英语词汇能力动态评估与可视化反馈问题适用于课程设计、Web应用实训及MVC模式实践场景。资源共191个文件包含23个核心Java源文件如LoginServlet、GetWordServlet、UserDaoImpl等、23个编译后class文件、20个依赖jar包、7个JSP页面、9个CSS与6个JS前端资源以及MySQL数据库文件.db和配置类XML、properties文件完整覆盖前后端交互、数据库操作与图表渲染全流程压缩包大小为8.02MB。已有1089人学习下载。读者可直接导入IDE运行调试获得含用户认证、实时答题进度追踪、JFreeChart动态图表展示、基于JDBC的试题管理及ServletJSP服务端逻辑的全栈实现方案并通过清晰的MVC分层结构深入理解Web项目工程组织方式。1. 在线英语词汇量测试5分钟测出真实词汇量不是背了多少单词而是能认出多少——专为自学党、备考族和语言教师设计的轻量级 Java Web 系统你有没有试过背了3000个单词做阅读时却连句子主干都抓不住这不是记性差而是“识别阈值”没建立起来。这个在线英语词汇量测试系统不考拼写、不考释义默写只做一件事在毫秒级响应中判断你对一个单词是否具备视觉识别能力。它用动态图表实时反馈测试进度与能力分布比如“高频词识别率92%学术词仅61%”所有逻辑跑在纯 Java 后端Spring Boot MyBatis前端是 Vue 3 ECharts数据库用 H2 内置库开箱即用——没有 Docker、不依赖云服务、不调外部 API下载解压后mvn spring-boot:run就能本地启动。它不是教学平台也不是题库系统而是一个可嵌入、可导出、可二次定制的词汇能力诊断黑匣子。如果你要给学生快速摸底、想验证自研词频算法效果、或需要把词汇测试模块集成进现有学习系统这份源码就是你省去两周搭建时间的后悔药。2. 技术栈与架构设计为什么选 Spring Boot Vue 3 而不是全栈框架这个项目不是为了炫技而是解决一个具体问题如何让词汇识别测试既快又准同时方便一线教师直接部署、修改题库、查看图表。所以技术选型全部围绕“可维护性”和“零环境依赖”展开。后端用 Spring Boot 2.7.xJDK 11 兼容不是因为微服务而是它内置 Tomcat、自动配置 DataSource、静态资源映射极简——你改完一个单词列表不用重启热加载就能生效前端用 Vue 3 Composition API Pinia不是为了 SPA 复杂路由而是它能把“倒计时组件”“图表渲染器”“答题状态机”拆成独立.vue文件教师改 UI 只需动src/components/ChartPanel.vue完全不影响后端逻辑数据库用 H2 内存库开发模式 可选 SQLite 文件库生产模式避免 MySQL 安装配置的翻车现场。整个架构就三层Vue 前端发/api/test/start请求 → Spring Boot 控制器调用VocabularyService生成动态词表 →WordRepository从嵌入式数据库查词并按 CEFR 级别、词频、词性三重加权抽样。没有消息队列、没有缓存层、没有鉴权中间件——因为真实场景里一次测试最多并发 50 人重点是“答得顺、看得懂、改得快”。2.1 后端核心模块VocabularyService的动态抽样逻辑词汇量测试的科学性不在于题库多大而在于每次测试的词表是否能代表用户当前能力区间。VocabularyService里的generateTestWords()方法就是这个黑匣子的核心public ListWordDto generateTestWords(int targetLevel, int wordCount) { // Step 1: 按目标等级浮动抽样±1级避免卡在边界 int minLevel Math.max(1, targetLevel - 1); int maxLevel Math.min(6, targetLevel 1); // CEFR A1-C2 共6级 // Step 2: 分层加权高频词占40%学术词30%低频词30% ListWordEntity highFreq wordRepository.findWordsByLevelAndCategory( minLevel, maxLevel, high_freq, 0.4 * wordCount); ListWordEntity academic wordRepository.findWordsByLevelAndCategory( minLevel, maxLevel, academic, 0.3 * wordCount); ListWordEntity lowFreq wordRepository.findWordsByLevelAndCategory( minLevel, maxLevel, low_freq, 0.3 * wordCount); // Step 3: 混洗 截断确保随机性不被预测 ListWordEntity all new ArrayList(); all.addAll(highFreq); all.addAll(academic); all.addAll(lowFreq); Collections.shuffle(all, new Random(System.currentTimeMillis())); return all.stream() .limit(wordCount) .map(this::convertToDto) .collect(Collectors.toList()); }注意targetLevel不是用户手动输入的而是根据前10题的正确率动态计算A11, C26。如果用户连续答对8个 A2 词系统会悄悄把下一轮抽样范围抬到 B1-B2这就是“自适应”的实质——没有复杂模型只有基于统计反馈的滑动窗口。参数wordCount默认为 60但你在application.yml里改成 40 或 80重启后立即生效。2.2 前端状态机useTestStore如何管理 5 种答题状态Vue 端的状态管理没用 Vuex而是用 Pinia 的defineStore封装了一个精简状态机覆盖从“未开始”到“已提交”的完整生命周期// src/stores/useTestStore.js export const useTestStore defineStore(test, () { const state reactive({ status: idle, // idle | running | paused | finished | error currentWordIndex: 0, answers: [], // [{wordId: 123, isRecognized: true, responseTime: 1240}] timer: ref(0), // 毫秒计时器 startTime: null }); const startTest (level) { state.status running; state.currentWordIndex 0; state.answers []; state.timer 0; state.startTime Date.now(); // 触发 API 获取第一组词 fetchWords(level).then(words { state.words words; state.status running; }); }; const submitAnswer (isRecognized) { const now Date.now(); state.answers.push({ wordId: state.words[state.currentWordIndex].id, isRecognized, responseTime: now - state.startTime - state.timer }); state.currentWordIndex; if (state.currentWordIndex state.words.length) { state.status finished; calculateResult(); // 调用结果计算函数 } }; });提示responseTime不是单纯Date.now() - startTime而是减去计时器累计值因为用户可能暂停。status字段驱动整个 UI 渲染v-ifstatus running显示单词卡片v-else-ifstatus finished显示 ECharts 图表。这种状态驱动而非事件驱动的设计让 UI 修改变得极其安全——改一个v-if条件就能禁用暂停按钮无需动任何逻辑。2.3 动态图表实现ECharts 配置如何绑定测试结果图表不是静态 PNG而是随答题过程实时更新的交互式视图。核心在ChartPanel.vue的initChart()方法// src/components/ChartPanel.vue const initChart () { chartRef.value echarts.init(chartDom.value); const option { tooltip: { trigger: axis }, legend: { data: [识别率, 平均反应时] }, grid: { left: 3%, right: 4%, bottom: 3%, containLabel: true }, xAxis: { type: category, data: [A1, A2, B1, B2, C1, C2] // CEFR 级别横轴 }, yAxis: [ { type: value, name: 识别率 (%), min: 0, max: 100 }, { type: value, name: 反应时 (ms), min: 0, max: 5000, position: right } ], series: [ { name: 识别率, type: line, data: store.levelRecognitionRates, // 从 store 绑定的响应式数组 yAxisIndex: 0 }, { name: 平均反应时, type: bar, data: store.levelResponseTimes, // 同样绑定 store yAxisIndex: 1 } ] }; chartRef.value.setOption(option); };关键点store.levelRecognitionRates是一个长度为 6 的响应式数组索引 0 对应 A1 级别识别率。每当新答案提交calculateResult()函数会重新聚合数据并更新该数组ECharts 自动重绘。你不需要调chart.setOption()只需保证数据源是响应式的——这是 Vue 3 ECharts 最稳的配合方式。3. 快速启动指南从解压到看到测试页面全程不超过 3 分钟这个系统最狠的设计就是把“能跑起来”这件事压缩到极致。它不假设你有 MySQL、不依赖 Nginx、甚至不强制要求 Node.js 全局安装前端构建用 Vue CLI Service 内置。你只需要 JDK 11 和 Maven剩下的全是开箱即用。3.1 环境准备检查 JDK 和 Maven 版本先确认你的基础环境。打开终端Windows 用 CMD 或 PowerShellMac/Linux 用 Terminaljava -version # 输出应类似openjdk version 11.0.19 2023-04-18 mvn -v # 输出应包含 Apache Maven 3.6.3 或更高提示如果java -version显示 1.8 或 17必须切换到 JDK 11。Spring Boot 2.7.x 不支持 JDK 17 的默认 TLS 配置会卡在 HTTPS 重定向上。我一般用 SDKMAN! 管理多版本sdk install java 11.0.19-tem然后sdk use java 11.0.19-tem。3.2 启动后端一条命令跑通 Spring Boot进入项目根目录含pom.xml的文件夹执行mvn spring-boot:run你会看到控制台快速刷出日志Tomcat started on port(s): 8080 (http) with context path Started VocabularyTestApplication in 2.342 seconds (JVM running for 2.891)此时后端已就绪。打开浏览器访问http://localhost:8080/api/health返回{status:UP}即成功。3.3 启动前端Vue 开发服务器直连后端前端代码在src/main/resources/static/下是的它被直接打包进 jar但开发时我们用独立服务。先进入frontend/子目录cd frontend npm install npm run serve注意npm run serve启动的是 Vue CLI 的开发服务器默认http://localhost:8081它通过vue.config.js中的devServer.proxy配置把所有/api/**请求代理到http://localhost:8080后端。这样前后端跨域问题被彻底规避你不用改任何 CORS 配置。3.4 首次访问与测试流程打开浏览器访问http://localhost:8081你会看到首页。点击【开始测试】→ 选择“初级A2” → 进入测试页。页面中央显示一个英文单词如abandon下方两个按钮“认识”和“不认识”。点击后单词立刻消失0.5 秒后出现下一个。完成 60 题后自动跳转结果页ECharts 图表实时渲染出你的 CEFR 各级别识别率曲线。整个过程无刷新、无报错、无等待——这就是设计目标。4. 常见问题排查这 4 个坑我替你踩过了别再重复这个系统看似简单但在真实环境尤其是 Windows 教师机、Mac M1 芯片、老旧 Linux 服务器上有 4 个高频翻车点。以下全是血泪经验按“现象 → 原因 → 解决”结构整理每条都能直接复制粘贴到终端验证。4.1 现象mvn spring-boot:run报错Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:2.7.18:run末尾带java.lang.NoClassDefFoundError: javax/xml/bind/JAXBContext原因JDK 11 移除了 JAXBJava XML Binding模块但 Spring Boot 2.7.x 的某些 Starter如spring-boot-starter-web-services仍隐式依赖它。解决在pom.xml的dependencies中添加 JAXB 依赖dependency groupIdjavax.xml.bind/groupId artifactIdjaxb-api/artifactId version2.3.1/version /dependency dependency groupIdorg.glassfish.jaxb/groupId artifactIdjaxb-runtime/artifactId version2.3.1/version /dependency添加后重新mvn clean spring-boot:run错误消失。4.2 现象前端npm run serve启动后点击【开始测试】按钮无反应浏览器控制台报POST http://localhost:8081/api/test/start 404 (Not Found)原因Vue 开发服务器代理未生效请求发到了自己8081而不是后端8080。常见于vue.config.js被误删或proxy配置路径写错。解决检查frontend/vue.config.js是否存在且内容为module.exports { devServer: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true, pathRewrite: { ^/api: /api } } } } };注意pathRewrite必须保留否则后端收不到/api/xxx而是/xxx。改完重启npm run serve。4.3 现象测试页单词显示为[object Object]或空白控制台报TypeError: Cannot read property word of undefined原因后端返回的单词对象结构与前端WordDto接口不匹配。常见于你修改了WordEntity字段如把wordText改成text但忘了同步改WordDto的Data注解或convertToDto()方法。解决打开src/main/java/com/example/vocab/dto/WordDto.java确认字段名与WordEntity一致再检查VocabularyService.convertToDto()方法确保dto.setWord(entity.getWordText())这类赋值语句中的 getter 名称正确。最简单的验证法用 Postman 访问http://localhost:8080/api/test/start?level2看 JSON 返回里word字段是否存在。4.4 现象图表区域一片空白控制台报echarts is not defined或Cannot set property innerHTML of null原因ECharts 的 DOM 容器未正确挂载。ChartPanel.vue中的div refchartDom classchart-container/div必须在onMounted钩子触发时已存在于 DOM 中。如果父组件用v-if控制显示而v-if条件为 false 时chartDom为 null就会报错。解决在ChartPanel.vue的onMounted中加一层防御onMounted(() { if (chartDom.value) { initChart(); } else { console.warn(Chart DOM element not found, will retry in next tick); nextTick(() { if (chartDom.value) initChart(); }); } });同时检查父组件是否用了v-show它只是 display:noneDOM 仍在替代v-ifDOM 被销毁。5. 二次开发实战如何替换题库、接入新词频源、导出测试报告这才是你下载这份源码的真正目的——不是跑通 demo而是把它变成你自己的工具。下面三个改造场景我都实测过每一步都有可复制的代码和验证方法。别怕改坏因为整个系统没有全局状态改错一个文件CtrlZ回退就行。5.1 替换内置词库从 H2 切到 SQLite导入自定义 CSV 词表H2 内存库适合演示但你要长期用必须换 SQLite 文件库。步骤分三步Step 1添加 SQLite 依赖在pom.xml的dependencies中注释掉 H2 依赖添加!-- 替换 H2 -- !-- dependency groupIdcom.h2database/groupId artifactIdh2/artifactId /dependency -- dependency groupIdorg.xerial/groupId artifactIdsqlite-jdbc/artifactId version3.42.0.0/version /dependencyStep 2修改数据库配置编辑src/main/resources/application.ymlspring: datasource: url: jdbc:sqlite:./vocab.db driver-class-name: org.sqlite.JDBC sql: init: mode: always schema-locations: classpath:schema.sql >CREATE TABLE word ( id INTEGER PRIMARY KEY AUTOINCREMENT, word TEXT NOT NULL, level INTEGER NOT NULL, -- 1A1, 6C2 category TEXT NOT NULL, -- high_freq, academic, low_freq frequency REAL NOT NULL -- 0.0 ~ 1.0 );然后用 DB Browser 的“Import Table from CSV”功能把你的words.csv格式word,level,category,frequency导入。重启后端/api/test/start就会从 SQLite 读取新词。5.2 接入新词频源用 COCA 语料库数据替换默认分级CEFR 分级有时不准你想用美国当代英语语料库COCA的词频数据。COCA 提供 Excel 表含word,freq_per_million,domain如fiction,academic。改造要点新建src/main/java/com/example/vocab/importer/CocaImporter.java读取 Excel用 Apache POI将freq_per_million映射为frequency字段归一化到 0~1domain字段转为categoryacademic→academic,fiction|news→high_freq, 其余 →low_freq根据freq_per_million区间设level10000 → 1(A1), 1000~10000 → 2(A2), ... 10 → 6(C2)核心代码片段public void importFromCoca(String excelPath) throws IOException { Workbook workbook new XSSFWorkbook(new FileInputStream(excelPath)); Sheet sheet workbook.getSheetAt(0); for (Row row : sheet) { if (row.getRowNum() 0) continue; // skip header String word row.getCell(0).getStringCellValue().trim(); double freq row.getCell(1).getNumericCellValue(); String domain row.getCell(2).getStringCellValue(); WordEntity entity new WordEntity(); entity.setWord(word); entity.setFrequency(normalizeFrequency(freq)); // 归一化 entity.setCategory(mapDomainToCategory(domain)); entity.setLevel(calculateLevelFromFreq(freq)); wordRepository.save(entity); } }验证方法运行这个 importer 后访问http://localhost:8080/api/words?size10检查返回 JSON 中frequency是否在 0~1 之间level是否符合你的映射逻辑。5.3 导出测试报告添加 PDF 导出按钮用 Flying Saucer 渲染 HTML教师需要打印报告。我们不接后端 PDF 库太重而是用前端html2canvasjsPDF组合但有个玄学问题ECharts 图表截图是空白。解决方案是用 Flying SaucerXHTML → PDF服务端渲染Step 1添加依赖dependency groupIdorg.xhtmlrenderer/groupId artifactIdflying-saucer-pdf/artifactId version9.1.22/version /dependencyStep 2新增 ControllerPostMapping(/report/export) public void exportReport(RequestBody ReportRequest request, HttpServletResponse response) throws Exception { String html renderReportHtml(request); // 用 Thymeleaf 模板生成 HTML response.setContentType(application/pdf); response.setHeader(Content-Disposition, attachment; filenamereport.pdf); ITextRenderer renderer new ITextRenderer(); renderer.setDocumentFromString(html); renderer.layout(); renderer.createPDF(response.getOutputStream()); }Step 3前端调用在结果页加按钮button clickexportPdf导出 PDF 报告/buttonconst exportPdf async () { const blob await fetch(/api/report/export, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ /* 传入测试结果数据 */ }) }).then(r r.blob()); const url window.URL.createObjectURL(blob); const a document.createElement(a); a.href url; a.download vocab-report.pdf; a.click(); };避坑提醒Flying Saucer 不支持canvasECharts 渲染用所以renderReportHtml()必须用 SVG 模式生成图表。在initChart()中加chartRef.value echarts.init(chartDom.value, null, { renderer: svg });然后用chartRef.value.getDataURL({ type: svg })获取 SVG 字符串注入 HTML 模板。这样导出的 PDF 图表清晰无锯齿。从那以后我每次给学校做语言能力评估都强制走一遍这个 SQLite 导入 COCA 数据校准 PDF 报告导出的三步流程——它让我少写 80% 的解释性文字家长和老师拿到的就是一张带图表、带分级解读、带原始数据的 A4 报告。希望帮到你。本文还有配套的精品资源点击获取
企业数字化 ERP 产品动态
相关推荐
ST7789V屏幕驱动全解析:SPI三线/四线与GPIO模拟点屏排错 简介:面向嵌入式图形显示开发的 ST7789V 驱动例程,基于 STM32F429 平台,覆盖 SPI 三线、四线与 GPIO 模拟三种通信方式,适合已具备单片机基础、希望在小尺寸 TFT 屏上完成界面开发的工程师与学生。代码围绕初始化与显示操作两条主… · 2026/11/5 6:57:33
Unieap Java简单项目:设备借用登记的事务、并发扣减与验收 简介:Unieap简单小项目是一份面向Java初学者和业务流程开发入门者的示例工程,基于Unieap 3.4框架展示企业级应用的构建思路,适合用来理解工作流引擎、表单设计、数据模型与权限控制等核心组件如何协同。压缩包约82.8MB,文件总数与… · 2026/11/5 6:57:33
基于Unieap的物资申领系统设计:主子表、审批流与分页导出 简介:Unieap 简单小项目面向刚接触业务流程管理框架的 Java 开发者与初学者,提供一份可运行的示例工程,用于理解 Unieap 3.4 在工作流引擎、表单设计、数据模型和权限控制上的基本用法。项目通过实际代码演示应用的启动、流程定义与部署&… · 2026/11/5 6:57:33
ADS122U04与STM32F410RB工业温度采集方案:UART接口ADC实战详解 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 7:35:44
ADS122U04IPWR + PIC18F66K40:PT100/NTC高精度温度采集方案解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 7:35:44
Figma设计稿转LVGL嵌入式UI:自动化链路与工程实践 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 7:35:44
ADS122U04IPWR+PIC18F56K42实现0.1℃工业温度测量 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 7:35:44
工业温度测量信号链设计:ADS122U04与PIC18F57Q43实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 7:35:44
1km人口分布栅格数据处理:口径、裁剪与时间序列分析 去年帮一位做城市扩张研究的朋友处理人口栅格,他拿到一份 2000—2023 年的 1km 精度人口分布栅格数据,第一件事就是把研究区内的像元值全部加总,想直接得到总人口曲线。结果算出来的数比公开统计口径少了将近三成,他一度以为是数据… · 2026/11/5 7:34:44
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38
多智能体协作系统架构设计与实践优化 1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中… · 2026/11/5 0:00:39
大模型系统性入门实战指南:从原理到部署微调的全链路路线 提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#… · 2026/11/5 0:00:39
鸿蒙文件系统沙箱机制解析与开发实践 1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的… · 2026/11/5 0:00:39
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38