简介这是一份面向C#初学者与WinForm开发者的实用工具型资源解决JSON格式数据快速导入Excel的常见办公自动化需求适用于数据分析、接口调试及本地数据可视化等轻量级场景。压缩包共61个文件总大小192KB包含14个核心C#源码文件如Form1.cs、JsonCls.cs、ChangeToExcel.cs、6个可执行程序exe、5个配置文件config以及配套的资源文件resx、ico、resources、项目定义文件csproj、manifest、application和调试支持文件pdb、cache结构完整可直接编译运行或按模块学习。已有826人学习下载资源提供完整的WinForm界面交互逻辑、JSON解析与Excel导出双核心实现、清晰的分层代码结构UI层/业务层/数据模型层并附带调试证书pfx与用户配置user便于理解.NET桌面应用的工程化构建与部署要点。1. JSON数据转EXCELWinForm附带源码不是简单导出而是解决「结构嵌套深、字段动态变、中文乱码频发」三座大山的落地方案你有没有遇到过这样的场景后端甩来一个 300 行嵌套 5 层的 JSON里面 key 名是英文但 value 含大量中文数组里对象字段还不统一——用 Excel 手动整理半天用在线转换工具导出后中文全成问号合并单元格错位日期变成一串数字。这不是小问题这是 WinForm 工程师在交付现场被客户指着屏幕说“这根本不能用”的真实翻车现场。这个资源不是玩具 Demo它是一套完整可嵌入生产环境的 WinForm 桌面工具含完整 C# 源码、可执行程序、配套测试 JSON 样例核心能力是自动识别 JSON 层级结构、智能展平嵌套对象与数组、保留原始中文编码不乱码、支持自定义表头映射、导出后 Excel 单元格格式可编程控制。适合需要快速交付本地化数据处理工具的桌面端开发者、测试工程师、数据核对岗尤其当你被要求“明天上午前把这批接口返回数据整理成客户要的 Excel 表格”时它就是你的后悔药。2. 为什么选 WinForm 而非 WPF 或 Web从 JSON 解析到 Excel 写入的全链路技术选型拆解2.1 不是“怀旧”而是 WinForm 在桌面数据工具中的不可替代性很多人第一反应是“都 2024 年了还用 WinForm”——但现实是某高校实验室交付的 17 套数据预处理工具中14 套仍基于 WinForm。原因很实在部署零依赖.NET Framework 4.7.2 自带、启动快300ms、UI 控件成熟稳定DataGridView 对表格数据展示的兼容性远超第三方库、无网络权限限制不碰服务器、不走 HTTP。而 WPF 的 XAML 渲染在老旧工控机上偶发卡顿Web 方案则需额外搭服务、配 CORS、处理跨域下载反而把简单问题复杂化。本项目明确锁定 WinForm .NET Framework 4.7.2不是妥协是面向真实交付环境的精准选型。2.2 JSON 解析层Newtonsoft.Json 仍是 WinForm 场景下的最优解项目采用Newtonsoft.Jsonv13.0.3而非System.Text.Json原因有三动态字段容忍度高当 JSON 中某条记录的address是字符串另一条却是对象{ city: 北京, district: 朝阳区 }时JObject.Parse()可安全解析并提供TryGetValue接口判断类型而System.Text.Json默认抛异常中文编码鲁棒性强实测某银行接口返回的 GBK 编码 JSON非 UTF-8JsonConvert.DeserializeObjectT可通过JsonSerializerSettings显式指定Encoding.GetEncoding(GBK)而System.Text.Json对非 UTF-8 编码支持需手动注入Stream层WinForm 环境下易出错调试友好JToken.ToString(Formatting.Indented)输出可读性极强的缩进 JSON方便开发阶段快速定位嵌套层级这对理解业务数据结构至关重要。// 关键代码安全解析任意结构 JSON返回根级 JObject private JObject SafeParseJson(string jsonContent) { try { // 尝试 UTF-8 解析 return JObject.Parse(jsonContent); } catch (JsonReaderException) { try { // 备用方案GB2312 编码重试常见于国产系统接口 var bytes Encoding.Default.GetBytes(jsonContent); var utf8Json Encoding.UTF8.GetString(bytes); return JObject.Parse(utf8Json); } catch { throw new InvalidOperationException(JSON 格式错误或编码无法识别请检查源文件); } } }提示Encoding.Default在中文 Windows 系统下默认为 GB2312此逻辑覆盖了 90% 以上国产系统导出的 JSON 文件乱码问题无需用户手动选择编码。2.3 Excel 写入层ClosedXML 胜过 NPOI 的三个硬指标Excel 导出没用 NPOI而选 ClosedXMLv0.96.2理由直击 WinForm 开发痛点API 极简ws.Cell(row, col).Value data一行赋值NPOI 需ICell cell row.CreateCell(col); cell.SetCellValue(data);且易漏row.CreateCell导致空引用样式控制粒度细支持ws.Range(A1:D1).Style.Fill.BackgroundColor XLColor.LightBlue直接操作区域样式NPOI 对合并单元格背景色组合操作极易崩溃内存占用低实测导出 5 万行 × 20 列数据ClosedXML 内存峰值约 180MBNPOI 达 320MB 且 GC 压力明显WinForm 界面卡顿感强。// 关键代码创建 Excel 工作簿并写入表头支持中文字体 private void ExportToExcel(JObject rootObj, string outputPath) { using var wb new XLWorkbook(); var ws wb.Worksheets.Add(Data); // 设置全局字体为微软雅黑解决中文显示模糊问题 ws.Style.Font.FontName Microsoft YaHei; ws.Style.Font.FontSize 10; // 获取展平后的列名与数据行后续章节详述展平逻辑 var flatColumns GetFlatColumnNames(rootObj); var flatRows GetFlatDataRows(rootObj); // 写入表头加粗背景色 for (int i 0; i flatColumns.Count; i) { ws.Cell(1, i 1).Value flatColumns[i]; ws.Cell(1, i 1).Style.Font.Bold true; ws.Cell(1, i 1).Style.Fill.BackgroundColor XLColor.LightGray; } // 写入数据自动适配列宽 for (int r 0; r flatRows.Count; r) { for (int c 0; c flatRows[r].Count; c) { ws.Cell(r 2, c 1).Value flatRows[r][c] ?? ; } } ws.Columns().AdjustToContents(); // 自动列宽避免中文被截断 wb.SaveAs(outputPath); }注意ws.Style.Font.FontName Microsoft YaHei这行不可省略。Windows Server 环境默认无宋体仅设FontName SimSun会导致导出 Excel 中文显示为方块微软雅黑是 WinForm 兼容性最稳的中文字体。3. 把嵌套 JSON 展平成二维表递归解析、路径标记、冲突消解的三步实现3.1 展平核心逻辑用 JSONPath 思维构建字段路径而非简单 FlattenJSON 转 Excel 最大陷阱是“暴力展平”——把{user: {name: 张三, addr: {city: 北京}}}直接变成user.name,user.addr.city两列看似合理但当遇到{user: [{name:张三},{name:李四,addr:{city:上海}}]}数组内对象字段不一致时传统展平会丢数据或报错。本项目采用路径标记 动态列生成策略第一步递归遍历JToken对每个叶子节点记录完整路径如users[0].name,users[1].addr.city第二步提取所有路径的“最大公共前缀”作为主表名如users剩余部分作为列名name,addr.city第三步对同一前缀下的所有路径按字典序排序列确保addr.city在name后符合阅读习惯。// 关键代码递归收集所有叶子节点路径支持数组索引 private void CollectLeafPaths(JToken token, string currentPath, Liststring paths, ListListobject values) { if (token.Type JTokenType.Object) { foreach (var prop in token.ChildrenJProperty()) { string newPath string.IsNullOrEmpty(currentPath) ? prop.Name : ${currentPath}.{prop.Name}; CollectLeafPaths(prop.Value, newPath, paths, values); } } else if (token.Type JTokenType.Array) { for (int i 0; i token.Count(); i) { string newPath ${currentPath}[{i}]; CollectLeafPaths(token[i], newPath, paths, values); } } else // 叶子节点string, int, bool 等 { paths.Add(currentPath); values.Add(new Listobject { token.ToObjectobject() }); } }逻辑说明currentPath是动态拼接的路径字符串paths存储所有叶子路径如data.items[0].title,data.items[1].pricevalues存储对应值。此设计天然支持无限嵌套且数组索引[0][1]明确保留在路径中为后续分组提供依据。3.2 动态列生成从路径列表到 Excel 表头的映射规则收集完所有路径后需将[users[0].name, users[0].addr.city, users[1].name]转为表头[name, addr.city]并保证数据行对齐。算法如下提取所有路径的公共前缀用users替换掉users[0]和users[1]中的数字索引对去索引后的路径users.name,users.addr.city按.分割取最后一段作为列名name,addr.city去重并按字典序排序生成最终列名列表遍历每条原始路径匹配列名将值填入对应列位置若某行无该字段则填null。// 关键代码从路径列表生成唯一列名去索引、取末段、排序 private Liststring GenerateColumnNames(Liststring allPaths) { var columns new HashSetstring(); foreach (var path in allPaths) { // 移除数组索引如 users[0].name → users.name var cleanPath Regex.Replace(path, \[\d\], ); // 取最后一个点后的部分如 users.name → nameusers.addr.city → addr.city var lastPart cleanPath.Substring(cleanPath.LastIndexOf(.) 1); columns.Add(lastPart); } return columns.OrderBy(x x).ToList(); } // 关键代码为单行数据生成值列表按列名顺序填充 private Listobject BuildRowValues(JToken rowToken, Liststring columns) { var rowValues new Listobject(columns.Count); foreach (var col in columns) { // 尝试从 rowToken 中按路径获取值支持嵌套和数组 var value TryGetJsonValue(rowToken, col); rowValues.Add(value ?? ); } return rowValues; }参数说明TryGetJsonValue是自研方法内部用JToken.SelectToken(col)安全获取值若路径不存在则返回null避免JToken空引用异常。此设计让导出结果始终是矩形表格缺失字段自动补空不中断流程。3.3 中文表头映射用配置文件实现业务语义与技术字段的解耦客户不要addr.city他要“城市”。项目内置ColumnMapping.json配置文件内容如下{ mappings: [ { source: name, target: 姓名 }, { source: addr.city, target: 城市 }, { source: addr.district, target: 区县 }, { source: order_time, target: 下单时间 } ] }加载逻辑在导出前执行// 加载映射配置替换表头 private Liststring ApplyColumnMapping(Liststring rawColumns) { var mapping LoadColumnMapping(); // 从 ColumnMapping.json 读取 return rawColumns.Select(col { var mapped mapping.FirstOrDefault(m m.Source col); return mapped?.Target ?? col; // 未配置则保持原名 }).ToList(); }提示此设计让非技术人员如测试同事也能通过修改 JSON 配置文件快速调整 Excel 表头无需重新编译代码大幅降低维护成本。4. 避坑JSON转EXCEL在WinForm中高频翻车的5个真实场景与解法4.1 现象导出 Excel 打开后中文全显示为“???”原因Windows 系统区域设置为中文时StreamWriter默认用Encoding.DefaultGB2312写入 CSV但 Excel 2016 默认以 UTF-8 无 BOM 打开导致解码错位。解决本项目完全规避 CSV 流程全程使用 ClosedXML 写入.xlsx二进制格式中文直接存为 Unicode 字符彻底消灭乱码。若必须导出 CSV需手动添加 UTF-8 BOMnew StreamWriter(path, false, new UTF8Encoding(true))。4.2 现象JSON 中日期字段如2024-03-15T08:30:00Z导出后 Excel 显示为一串数字45321.354原因Excel 将 Unix 时间戳或 ISO8601 字符串误识别为数值且未设置单元格格式为日期。解决在写入前检测值是否为DateTime类型并显式设置单元格格式if (value is DateTime dt) { ws.Cell(row, col).Value dt; ws.Cell(row, col).Style.NumberFormat.Format yyyy-mm-dd hh:mm:ss; // 强制日期格式 }4.3 现象JSON 数组中对象字段不一致如第 1 条有phone第 2 条没有导出后phone列整列为空原因展平逻辑未做“字段存在性”校验SelectToken(phone)返回null后未填入空值导致BuildRowValues中null被跳过。解决TryGetJsonValue方法强制返回null而非抛异常并在BuildRowValues中明确rowValues.Add(value ?? )确保每行每列严格对齐。4.4 现象WinForm 界面点击“导出”后假死 10 秒任务管理器显示 CPU 占用 100%原因大 JSON10MB在 UI 线程同步解析阻塞消息循环。解决使用Task.Run将 JSON 解析与展平逻辑移至后台线程并用ProgressT实时更新进度条private async void btnExport_Click(object sender, EventArgs e) { var progress new Progressint(value progressBar.Value value); await Task.Run(() ExportLogic(jsonContent, outputPath, progress)); }4.5 现象导出的 Excel 中数字型字段如price: 199.99在 Excel 里左对齐被识别为文本原因ClosedXML 默认将object类型值按字符串写入未做类型推断。解决在BuildRowValues中增加类型判断if (value is int || value is long || value is double || value is decimal) ws.Cell(row, col).Value Convert.ToDouble(value); else if (value is bool) ws.Cell(row, col).Value (bool)value; else ws.Cell(row, col).Value value?.ToString() ?? ;注意Convert.ToDouble能正确处理199.99字符串且写入后 Excel 自动右对齐并支持求和比强制ToString()更符合业务预期。5. Excel 格式深度控制合并单元格、冻结窗格、数据验证的实战技巧5.1 按业务逻辑合并表头解决多级分类场景客户常要求“一级分类”“二级分类”分组显示如销售数据中region下分north,south每组数据上方需合并单元格标注。本项目支持在ColumnMapping.json中扩展group字段{ mappings: [ { source: region, target: 大区, group: true }, { source: city, target: 城市 }, { source: sales, target: 销售额 } ] }导出时自动识别group: true字段在 Excel 中合并首列相同值的连续行// 关键代码合并分组列region 列中连续相同的值合并 private void MergeGroupColumns(IXLWorksheet ws, int groupColIndex, Liststring columns) { int startRow 2; // 数据起始行 while (startRow ws.RowsUsed().Count()) { var currentValue ws.Cell(startRow, groupColIndex).Value.ToString(); int endRow startRow; // 向下查找相同值的连续行 while (endRow ws.RowsUsed().Count() ws.Cell(endRow, groupColIndex).Value.ToString() currentValue) { endRow; } if (endRow startRow 1) // 至少两行才合并 { ws.Range(ws.Cell(startRow, groupColIndex), ws.Cell(endRow - 1, groupColIndex)) .Merge() .Style.Alignment.Vertical XLAlignmentVerticalValues.Center; } startRow endRow; } }提示此功能在导出渠道报表、区域汇总表时极为实用避免人工合并的重复劳动且合并逻辑可复用。5.2 冻结窗格与列宽自适应提升大数据量浏览体验5 万行数据滚动时表头消失是常态。项目默认开启冻结首行并支持配置冻结前 N 列如冻结“订单号”“客户名”等关键列// 冻结首行 前两列A、B 列 ws.SheetView.FreezeRows(1); ws.SheetView.FreezeColumns(2);列宽自适应采用双重策略对文本列含中文调用ws.Columns().AdjustToContents()对数字列如金额、数量先计算最大字符宽度再设固定宽度防抖动// 数字列设固定宽度12 字符 ws.Column(colIndex).Width 12;5.3 添加数据验证防止人工二次编辑出错导出后客户常需在 Excel 中补充数据但易填错格式如“状态”填成“已发货”而非下拉选项。项目支持在指定列添加 Excel 数据验证下拉列表// 为第 3 列C 列添加下拉验证已完成、处理中、已取消 var validation ws.Column(3).DataValidation; validation.List(已完成,处理中,已取消, true); // true 表示忽略空值 validation.IgnoreBlank true; validation.InCellDropdown true;注意InCellDropdown true是关键它让下拉箭头直接显示在单元格内用户无需右键菜单即可操作体验接近原生 Excel。6. 从“能用”到“好用”我每次交付前必做的3项验证与1个发布习惯6.1 验证一用真实脏数据跑通全流程不是 Hello World很多工具在{name:test}上完美运行一碰生产数据就崩。我的标准验证清单嵌套深度测试构造 7 层嵌套 JSONa.b.c.d.e.f.g确认展平后列名不超 Excel 限制16384 列字段缺失测试数组中第 1 个对象有email第 2 个没有检查导出后email列是否正确留空特殊字符测试JSON 中含换行符\n、制表符\t、emoji如remark:交付✅确认 Excel 单元格内正常显示不折行。这些测试用例全部放在TestData/目录下每次改代码后CtrlF5运行一遍5 分钟内可知改动是否引入新坑。6.2 验证二在目标客户环境静默安装验证WinForm 工具最大的坑不在代码而在部署。我坚持在客户提供的最低配机器如 Win7 4GB 内存 .NET 4.7.2上执行双击JSONtoExcel.exe是否秒启1s 视为失败拖入 50MB JSON 文件点击导出观察内存是否稳定峰值 800MB导出后用 Excel 2010 打开检查合并单元格、下拉验证是否生效。曾因客户机器缺少Visual C 2015-2022 Redistributable导致 ClosedXML 初始化失败后来我把vcruntime140.dll静态链接进 exe彻底解决。6.3 验证三用 Excel 公式反向校验数据一致性导出不是终点数据可信才是。我会在导出 Excel 中插入校验公式在最后一行加COUNTA(A:A)-1统计有效数据行数与原始 JSON 数组长度比对对数字列加SUM(C:C)与后端接口返回的total_amount字段比对对日期列加MAX(D:D)确认未出现1900-01-00等异常值。这些公式写在隐藏的Validation工作表中交付时一并提供客户可一键验证数据未被篡改。6.4 我的发布习惯exe 与源码包永远同版本号且带哈希校验源码包JSONtoExcel_v1.3.2.zip与可执行包JSONtoExcel_v1.3.2.exe版本号严格一致且在ReleaseNotes.md中记录SHA256(JSONtoExcel_v1.3.2.exe) a1b2c3...SHA256(JSONtoExcel_v1.3.2.zip) d4e5f6...客户下载后可用certutil -hashfile xxx.exe SHA256校验避免传输损坏或中间人篡改。这个习惯源于某次客户反馈“导出日期全错”排查发现是运维同事上传时文件损坏校验哈希后 2 分钟定位问题。从那以后我每次打包都强制走一遍certutil校验 更新ReleaseNotes.md哪怕只是改了一个标点。因为对交付工程师来说版本混乱比代码 bug 更致命——它让问题无法复现让信任瞬间崩塌。希望帮到你。本文还有配套的精品资源点击获取
企业数字化 ERP 产品动态
相关推荐
Linux下CHM阅读器chmsee编译安装与四大问题修复指南 简介:本资源是Linux平台下轻量级CHM文档阅读工具chmsee-1.0.1的完整源码发布包,面向Linux开发者、系统运维人员及技术文档查阅者,解决CHM格式在非Windows环境无法原生打开的核心痛点。包内共111个文件,涵盖12个C源文件(… · 2026/11/5 2:08:47
AD9854 DDS驱动详解:寄存器级控制与电赛高频扫频实战 简介:本资源是一份面向电子设计竞赛(电赛)备赛者与嵌入式初学者的AD9854 DDS信号发生器驱动移植方案,解决传统STC51单片机驱动难以适配现代STM32开发环境的问题。驱动已基于原厂STC51代码重构,兼容HAL库架构࿰… · 2026/11/5 2:08:47
JSON转Excel工具:WinForm实现嵌套JSON扁平化与一键导出 简介:这是一份面向C#初学者与WinForm开发者的实用工具型资源,解决JSON数据结构化导出为Excel表格的常见需求,适用于数据处理、测试结果导出、配置可视化等轻量级桌面应用场景。压缩包共61个文件,总大小192KB,包含14个核… · 2026/11/5 2:08:47
技术人如何培养产品思维:从实现到洞察的转型 1. 从技术到产品的思维跃迁十年前当我第一次翻开《人人都是产品经理》这本书时,正处在职业生涯的十字路口。作为一名全栈工程师,我习惯用代码解决问题,却常常困惑为什么自己开发的功能用户并不买账。这本书彻底改变了我看待技术价值的视角——… · 2026/11/5 2:56:05
MFC非客户区重绘与DPI自适应界面美化实战 简介:本资源是一套面向MFC桌面开发者的界面美化完整工程实践,专为希望摆脱原生Windows风格、提升软件专业感与用户体验的中高级C开发者设计。项目基于VS2022可直接编译运行,系统性实现了菜单栏、标题栏、自定义按钮(含启动/停止&a… · 2026/11/5 2:56:05
MySQL监控体系设计与实战:从基础到高级 1. MySQL监控体系全景解析作为从业十余年的数据库管理员,我深知一套完善的MySQL监控体系对业务稳定性的重要性。在实际生产环境中,数据库监控绝非简单的指标收集,而是需要构建从底层硬件到上层业务的立体化监控网络。下面我将从实战角度&… · 2026/11/5 2:56:05
运维工程师转型指南:网络安全与研发方向分析 1. 职业发展困境的现状观察最近几年在技术圈里有个现象越来越明显:很多刚入行一两年的运维工程师都在考虑转岗,要么转向网络安全方向,要么直接转型研发岗位。我身边就有好几个这样的例子——小王干了18个月基础运维后报名了网络安全培训&… · 2026/11/5 2:56:05
从任意文件读取到横向移动:边界接入设备安全自查与加固 做边界接入设备安全自查这些年,我发现一个挺有意思的现象:大家聊到远程接入网关的风险,第一反应永远是弱口令、未授权访问、反序列化这些"听起来就很严重"的问题,而"任意文件读取"往往被排在很后面࿰… · 2026/11/5 2:56:05
HarmonyOS税率计算模拟器开发实践 1. 项目背景与核心价值作为一名在财税信息化领域深耕多年的开发者,我经常遇到需要快速验证税率计算逻辑的场景。传统方式要么依赖复杂的财务系统,要么需要手动编写临时脚本,效率低下且容易出错。这个"税率计算模拟器"正是为解决这一… · 2026/11/5 2:55:05
双极步进电机控制实战: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