如果你的业务系统需要一个内嵌的在线表格能力Univer 这个名字值得你花十分钟了解一下。它是目前社区里比较少见的一个开源、可商用、还能直接做协同编辑的电子表格 SDK前端项目可以直接引入把类似 Excel 的操作体验搬到网页里整体体验远好于那些沉重的 iframe 套壳方案。这篇文章我会从架构、接入、劫难问题三个层面把我在真实项目里用过、验证过的东西讲清楚适合正在做 SaaS、低代码平台、数据后台、内部工具或者被繁琐表格交互折磨的前端团队参考。1. 先说结论Univer 是什么解决什么问题1. 先说结论Univer 是什么解决什么问题很多人第一次看到 Univer 的官网第一反应是这不就是又一个在线 Excel 组件吗。但如果你真正做过嵌入式表格需求就明白市面上能把这件事做通透的开源方案其实一直很缺。先说它的定位Univer 是一个面向开发者的开源 Web 电子表格 SDK目标不是做一个完整的产品而是把电子表格的核心能力拆成可嵌入的模块让你在自己的 Web 应用里快速生成一个具备公式、样式、合并单元格、筛选、排序、批量编辑、协同编辑等能力的表格界面。换句话说它解决的是我自己的业务系统需要一个能填数据、算数据、展示数据的表格引擎而不是我打开一个网页去编辑一份 Excel 文件。从使用方式看它跟一些传统税件不一样。Univer 的底座是纯前端的渲染引擎有自己的数据模型和交互框架。你调用 API 创建 Workbook往单元格里填数据可以写公式字符串可以套样式可以监听用户改动了某个单元格也可以直接从数据层取整个表格的快照。所有的 UI 都是画出来的不是浏览器里一个个真实 DOM 表格单元格这在性能上是一个质的差别。拿我自己做过的场景举例团队之前维护一个运营后台里面需要让业务人员直接维护一份广告投放排期表。表里有合并单元格、带下拉选择的渠道列、跨 sheet 的公式引用。最初方案是嵌入开源的 x-spreadsheet再加一堆自定义按钮效果勉强能用但遇到 10 万行以上数据时拖动滚动条就开始肉眼可见地卡顿协同编辑更是完全没法奢望。后来调研了一圈切换到 Univer同样的数据量滚动流畅公式能算代码层面还能直接用 API 控制 sheet 之间的引用整体改造成本比预想低很多。Univer 适合谁来用其实分成三类第一类是前端团队想在产品里嵌入表格希望以本地组件的方式使用而不是引入重型解决方案第二类是低代码平台开发者需要把表格作为一种可配置控件暴露给用户第三类是那些做数据采集、报表、审批流、教学平台这类偏工具属性的产品团队不想自己从零实现 Excel 交互又不想被商业组件卡脖子。如果你只是需要一个只读的表格展示组件Univer 有点杀鸡用牛刀但一旦涉及复杂编辑、联动计算、协作它就比普通表格库实用太多。2. 拆解 Univer 的核心架构与设计思路2.1 一切皆插件功能按需加载Univer 的第一大设计亮点是它把系统分成了核心 (core)和插件 (plugins)两层。核心只维护工作簿、工作表、单元格数据模型等最小概念公式计算、渲染、复制粘贴、筛选、排序这类功能全部以插件形式挂载。启动时你只加载自己需要的插件不需要的就不带既控制了包体积也避免了某些功能模块互相干扰。这个设计对项目维护者来说非常友好。我自己在接入时只需要选一个包含常用插件的preset比如univerjs/preset-sheets就有完整的表格编辑能力。等后续想引入图表或权限控制再动态配置对应插件不影响现有数据结构。理解它的插件机制之后再回看之前用 monorepo 管理模块的思路其实就是同一套逻辑。2.2 数据模型与公式网络用生活化的类比来说Univer 把表格想象成一个有坐标的数据库。每个单元格存的值用类似0!0这样的坐标字符串来寻址前面的数字代表行号后面的数字代表列号底层数据模型里存的不只是显示文本还包括数据类型、样式、公式、合并信息等元数据。这样做的好处特别明显任何 UI 变化都只是一层投影模型的更新底层数据始终有序。更让我看重的是它的公式引擎。Univer 的公式不是简单地把字符串丢给某个 eval 函数而是构建了一张公式依赖网络。比如 A1 的值 B1 C1B1 又 D1 * 2当你改了 D1 的时候系统能沿依赖链自动重算 A1、B1而不是粗暴地全表重算。这个能力在数据联动比较复杂的业务场景里帮了大忙比如月度汇总依赖每日明细明细一变汇总马上更新体验上接近原生 Excel 的计算逻辑。2.3 渲染引擎为什么敢接大数据量传统表格库很容易出现一操作就白屏的尴尬。因为每个可见单元格可能都是一个 DOM 节点十个格子就是十个 DOM别说百万级数据几万行的表格打开都有卡顿感。Univer 的做法是使用 Canvas 来渲染表格区域相当于把整个可视区当成一张图来画滚动时只绘制当前视口内的内容配合虚拟滚动真正处理几十万行数据时性能依然在线。当然Canvas 也不是万能钥匙。它带来的代价是原本用浏览器原生 DOM 实现的某些可访问性能力、输入框交互需要重头实现一套。Univer 在输入方面做了很细的处理包括中文输入法的组合输入状态、光标定位、选区绘制这些细节我实测下来表现稳定说明团队在底层做了不少硬功夫。这也侧面说明它不只是一个表面的画布表格而是真正把交互层建在了渲染层之上。2.4 协同能力从保存后刷新变成实时操作协同编辑是 Univer 跟很多开源表格库拉开差距的关键。它不是每隔几秒拉一次数据的伪协同而是在数据模型之上实现了操作日志的同步机制。大概思路是每个用户的编辑动作会被记录成操作指令下发到服务端再广播给其他客户端客户端收到操作指令后合并到本地数据模型同时处理冲突。这样架构下两个人同时改同一个单元格时系统可以基于时间/逻辑顺序做出最终一致性处理而不是互相覆盖。在接入协同之前最好先把单机版的数据快照机制吃透。因为协同本质上是把本地快照作为基准、操作日志作为增量的不断同步过程。如果你服务端能提供快照存储和 WebSocket 通道那接入协同的思路就会非常清晰客户端初始化时用最新快照渲染操作期间把 op log 实时上传和收发。官方也有一些合作/实现示例可以作为参考但它启用的不是一层简单的保存按钮而是需要你对接后端的实时通道。3. 快速上手把 Univer 从零跑起来3.1 安装依赖与容器准备先把包装好目前核心依赖和预设推荐如下npm install univerjs/core univerjs/preset-sheets # 如果后续要补公式、图表等能力再根据文档安装对应扩展包需要注意 Node 环境和包管理器版本。我踩过的一个坑是项目还在用比较老的 Node 版本安装时提示某些依赖编译失败后来升级到 Node 18 并清理 node_modules 重新装才正常。这是前端项目的老问题但遇到 Univer 这种比较新、依赖较前沿的库时尤其明显。容器方面需要一个有确定高度的 DOM 元素Univer 会在里面挂载渲染画布div idapp styleheight: 600px/div高度的写法很关键。如果父容器高度是auto或者0页面出来就是一片空白早期接入的人十个里至少有五个在这里卡壳。3.2 最简单的初始化代码推荐直接用预设方式一下子把表格能力都启动起来import { Univer } from univerjs/core; import { univerSheetPreset } from univerjs/preset-sheets; const univer new Univer( univerSheetPreset({ container: document.getElementById(app), locale: zhCN, }) );这段代码做完之后页面里已经出现一个空白的 Excel 界面可以输入、拖拽填充、合并单元格。之所以能用这么少的代码启动是因为预设包内部已经把渲染插件、表格插件、公式引擎、交互插件都组合起来了。如果你对包体积有要求或者只想要只读能力那就要回到按需插件的思路手动引入 UniverRenderEnginePlugin、UniverSheetsPlugin 等一个一个组合。初始化之后通常还要创建工作簿否则画布上是没有任何 Sheet 的const workbook univer.createWorkbook({ sheets: [ { id: sheet-1, name: 第一张表, cellData: { 0!0: { v: 项目 }, 0!1: { v: 预算 }, }, }, ], });createWorkbook接收的就是一个 workbook 的 snapshot 数据结构。cellData里的 key 是行!列的坐标写法值是单元格对象v代表纯文本或数值。这个结构跟后面做数据导入导出是同一套非常直观。3.3 写入数据、公式和样式业务开发中我们更常做的不是让用户手动填而是把接口数据塞进表格。可以直接操作 cellData 然后创建 workbook也可以在运行时通过 API 修改某个单元格// 通过初始 snapshot 写公式 cellData: { 0!2: { f: SUM(B1:B5) }, // f 代表 formula } // 运行时获取当前 sheet 操作 const sheet univer.getActiveWorkbook().getActiveSheet(); sheet.getRange(0, 0, 1, 1).setValue(Hello Univer);这里要特别提醒公式字段里别漏掉,别用中文引号别在一个格子里同时写v和f。因为优先级是公式计算结果覆盖静态值。如果你写入{ v: 10, f: B1C1 }最后显示的往往不是 10而是公式的计算结果。样式方面可以给单元格设置背景、字体、边框、对齐方式常见的做法是直接定义在 cellStyle / rowData / colData 里。但从实际接入经验来看最省心的路径是先做一个简单的 Excel 模板用 Univer 打开后调接口获取 snapshot再做程序化修改。这样样式细节由模板接管代码里只需要关心数据本身。3.4 在 React/Vue 项目中集成以 React 为例核心思路是在组件挂载时初始化 Univer在卸载时清理实例避免内存泄漏和重复渲染。import { useEffect, useRef } from react; import { Univer } from univerjs/core; import { univerSheetPreset } from univerjs/preset-sheets; export default function SheetEditor() { const containerRef useRefHTMLDivElement(null); useEffect(() { if (!containerRef.current) return; const univer new Univer( univerSheetPreset({ container: containerRef.current, locale: zhCN, }) ); univer.createWorkbook({ sheets: [{ id: s1, name: Sheet1 }], }); return () { univer.dispose(); }; }, []); return div ref{containerRef} style{{ height: 600px }} /; }在 Vue 里也类似把初始化逻辑放到onMounted/onBeforeUnmount中。我见过一些新手直接把 Univer 实例建在全局单例里导致切换页面时上一个表格还残留在内存里数据混乱甚至出现两个表格互相监听事件的问题。老老实实按生命周期管理实例反而是最稳的。还有一点如果你在 React 的 StrictMode 下开发初始化函数会被调用两次这时dispose的清理逻辑就显得非常重要。我在实测中发现没有做清理的情况下StrictMode 会同时挂载两个 canvas 实例出现重叠闪烁。3.5 从 Univer 获取用户修改后的数据用户编辑完之后肯定要提交数据到后端。获取整张表的内容有几种方式我建议用快照方式const workbook univer.getActiveWorkbook(); const snapshot workbook.getSnapshot(); // snapshot 中包含 sheets、cellData、styles、merge 等信息拿到快照后你可以把 cellData 序列化成 JSON 提交给后端存储下次回显时再把这个 JSON 原封不动传回createWorkbook。如果你的业务只需要提交用户改了哪些格子更轻量的做法是监听单元格变更事件增量上报。这两种模式各有用处但在大多数后台表单场景里全量快照更简单直观也更容易排查问题。4. 进阶玩法把 Univer 往企业级场景里推4.1 封装一个低代码表格组件Univer 用起来顺手但直接暴露给低代码平台的可视化配置器使用并不合适。它暴露的 API 是面向开发者的你需要再包一层更友好的组件接口。我通常会封装一个SchemaSheet组件它接收三个基础 propscolumns列配置包含标题、宽度、类型、dataSource数据源数组对象、readOnly是否只读然后在内部把 columns 映射成表头行、把 dataSource 映射成数据行。映射关系不复杂但有一个重要细节如果你的 dataSource 是对象数组而表格需要保留每一行的业务主键建议同时在隐藏列或者单元格注释里写入主键值不要假设行号等同于业务 ID。因为用户插入行、删除行之后行号会变不加主键追踪会导致提交的数据错乱。等用户编辑完毕再通过主键把表格数据合并回业务数据结构。封装完成后低代码平台只需要通过 JSON Schema 配置列和校验规则就能快速生成一个可在线编辑的数据表格实例这也是 Univer 在当前低代码市场里被频繁采用的核心原因。4.2 协同编辑的接入思路如果要在生产环境做多人同时编辑同一张表必须先搞清楚 Univer 协同工作的数据流。简单说分为两部分客户端通过 Univer 的协同扩展把本地操作封装成 op log发送到服务端同时接收远端 op log合并进本地数据模型。服务端负责快照存储、op log 广播和权限校验。官方有协作示例也提供了协同思路但生产环境大概率需要你自建 WebSocket 服务和存储层。从实操角度看接入协同前一定先设计好谁有权限改哪张表。线上协同的坑不只在于实时同步更在于权限、并发冲突和错误恢复。我的建议是MVP 阶段先做到同步也就是两个人同时看到新数据第二步再做到冲突解决比如同一个格子被两个人同时修改时采用后写覆盖还是提示用户选择第三步才是历史版本回滚。很多人一开始就追求全量协同导致项目迟迟上不了线。另外协同环境下的公式重算也要留意。如果 A 用户在改数据时 B 用户也在改依赖数据最终的汇总结果可能取决于 op log 的合并顺序。单机场景里没问题协同场景里要牢记最终一致性不等于强一致性。4.3 大数据量渲染与性能优化先说结论Univer 处理大数据量的能力在开源方案里属于第一梯队但也不是无脑堆数据就会快。数据量上去之后影响最大的不是渲染而是公式依赖图的维护和复制粘贴操作。优化建议有这么几条开启虚拟滚动是默认行为不要关闭它才是流畅滚动的关键。高频更新的单元格尽量少用整列引用公式比如A:A这种写法在数据量大的情况下会影响计算性能最好明确成A1:A1000。不要让每个单元格都设置独立样式。样式对象越多快照数据越大保存和回显都会变慢。尽量使用整表样式或者行列级别样式。如果你只是做只读展示可以在初始化时去掉公式引擎插件只保留渲染和选区。少了计算模块内存占用会明显下降。我用一份 20 万行、12 列的模拟数据实测过初始化渲染大概在 1 秒左右滚动没有明显迟滞。数据是完全够用的但相对比较吃内存移动端低端机慎入。表格没法做成纯文本写一个函数把 cm 转换成 px。开头不必太在意格式关键是让用户在本地 Excel 里看到预期的数据别让正负号变成了科学计数法这种历史问题再次上演。4.4 导入导出 Excel 的实际经验Univer 本身在前端渲染上很优秀但导入导出 Excel一定不要依赖它原生去读.xlsx尤其是涉及复杂样式时。我的做法是采用中间人模式后端用专业的 Excel 处理库生成/解析真正的.xlsx同时后端把表格内容转换成 Univer 能识别的 JSON 数据结构返回给前端前端只接收这个 JSON 并通过createWorkbook渲染。如果非要在前端直接导入可以先用 SheetJS 之类工具读取.xlsx内容转成二维数组或对象数组再手动映射到 cellData。这个过程你会发现最大的问题Excel 单元格的样式信息颜色、边框、合并在纯 JS 解析库里往往拿不全。所以如果是非走前端导入不可的演示场景建议只导入数据、不导入样式省得用户看到一半乱掉。导出反向同理存储的 Highscore 实际上就是 JSON 而不是.xlsx需要 Excel 文件时可以让后端把 JSON 转回.xlsx再发下载链接。在后端转换这一步还要处理日期格式、数字精度、公式缓存值否则导出的文件在 Excel 里打开时会显示公式结果为空或日期偏移。5. 常见问题与避坑实录5. 常见问题与避坑实录5.1 白屏、容器高度和初始化时机这是出现频次最高的问题几乎覆盖了一半的新手提问。白屏原因通常不是代码写错而是容器高度为 0。回想一下Univer 的渲染画布是绝对定位铺满容器的容器如果没有高度画布自然会塌缩成一条线甚至完全不可见。解决方法是给外层 div 一个显式高度或者在初始化前用getBoundingClientRect()检查容器尺寸。还有一个容易忽略的场景如果你在 Tab 切换时才初始化表格而 Tab 内容在初始化那一刻是display: none状态容器也是 0 宽高Univer 同样会白屏。解决思路是等 Tab 切换到对应面板容器可见后再初始化或者初始化完成后调用 resize 相关方法刷新尺寸。5.2 公式不计算、显示为0公式写入后却不生效多半是漏了公式插件。使用简单初始化的预设时一般没问题但如果你按需引入插件记得把 FormulaEnginePlugin 加进去否则公式字符串会被当成普通文本显示。这个问题的典型现象是单元格显示SUM(A1:A5)而不是计算结果检查插件清单基本能定位。还有一种情况是公式语法在 Univer 里不被支持。Univer 对常用函数兼容得不错但某些新函数或数组公式可能与 Excel 有细微差异。遇到公式结果显示#NAME?时先确认 Univer 文档里的支持函数列表不要一上来就怀疑数据问题。5.3 与 React StrictMode 的冲突React 18 的 StrictMode 会让useEffect执行两次如果初始化代码没有对应的dispose页面上会出现两个叠加的 canvas或者第二个实例直接抛错。核心思路就是初始化函数把 Univer 实例存进 ref清理函数里调用univer.dispose()并把 ref 置空。这样即使 StrictMode 执行两次也能正常创建-销毁-创建。如果你发现自己怎么清理都没用还可以在组件外面加一个模块级标志位阻止重复创建。这不是最优解但在项目代码混乱时往往是快速止血的办法。5.4 版本升级带来的破坏性变更Univer 目前还在快速迭代期0.x 版本之间的 API 差异不小。最典型的就是工作簿创建方法从早期版本的createUniverSheet改名成了现在的createWorkbook插件注册方式也从数组式配置调整成了预设函数。如果你从网上搜到一篇几个月前的教程直接复制代码大概率跑不起来。我的经验是优先看当前版本的官方文档和 release notes搜到旧代码时先看一眼包的package.json版本号然后去官方 CHANGELOG 确认变更点。另外遇到明明对着文档写却不生效的情况很有可能是你当前项目里同时存在多个版本的 Univer 包这时就用npm ls univerjs/core查一下依赖树锁掉重复版本。这些坑都不是什么不可逾越的大山但如果你提前知道至少能少摔几次。尤其是对刚接触 Univer 的团队来说找对版本、配好容器、理清数据模型和插件加载之间的关系后面基本就是一马平川。我从第一次在这个项目上尝到甜头到现在已经把它从单纯的表格展示扩展成了我们低代码平台的默认表格控件。Univer 的真正价值不在于又一个表格而在于它给 Web 表格注入了一种现代前端的工程化思维让开发者不必再从 DOM 层开始造轮子。如果你手头正好有一个表格需求同时又烦透了各种商业授权费和维护半死不活的老旧开源项目我建议你花一个下午把 Univer 拉起来试试。它的学习成本不算高但回报率在同类工具里确实数一数二。
企业数字化 ERP 产品动态
相关推荐
企业级大模型网关架构设计与Java实践 1. 企业级大模型接入的现状与挑战最近两年,大模型技术在企业应用中的渗透率显著提升。根据行业调研数据显示,超过67%的中大型企业已在生产环境中尝试接入大模型能力。但在实际落地过程中,工程师们普遍面临着几个棘手问题:协议差异… · 2026/11/3 5:53:10
零基础通达信公式入门:从公式管理器到均线选股实战 简介:《通达信公式编写教程完整版》面向具备一定开发基础、希望系统入门通达信公式编写的学习者,帮助梳理公式类型、函数调用和指标编写的基本路径。资源包共1个文件,为doc文档,压缩包约1MB,内容集中,目录结… · 2026/11/3 5:53:10
Buzz技术概念解析:从声学信号到交互反馈 我无法基于当前输入生成符合要求的博文。原因如下:项目标题仅为单个英文单词"buzz",无明确领域指向(可指声音、社交热度、技术术语如蜂鸣器信号、营销传播中的“口碑传播”、编程中某库/工具名、甚至俚语用法)ÿ… · 2026/11/3 5:53:10
MemTest86内存测试工具使用指南与实战技巧 1. 为什么需要专业内存测试工具在Windows 11系统下,内存故障往往表现为最难以诊断的随机性问题。我遇到过多次蓝屏死机案例,表面看是系统或驱动问题,实际却是内存颗粒的间歇性故障。与CPU或显卡故障不同,坏内存的症状具有以下特征… · 2026/11/3 6:25:25
如何制造buzz?从话题抓手到传播扩散的完整方法论 “buzz”是我最近反复琢磨的一个词。它不像“流量”“转化”那样一上来就有明确数字,但几乎决定了一个东西能不能在人群里自己跑起来。入行新媒体这么多年,做品牌投放、内容策划、账号孵化都摸过,身边人嘴上特别爱说“做点动静出来”… · 2026/11/3 6:25:25
易加增材3米级金属3D打印机技术解析与应用 1. 易加增材的3米级金属3D打印机技术突破在金属增材制造领域,设备成型尺寸一直是制约行业应用的关键因素。传统金属3D打印机的成型尺寸多在500mm以下,难以满足航空航天、能源装备等大型工业部件的制造需求。易加增材最新推出的3米级金属3D打印机… · 2026/11/3 6:25:25
在Node.js中运行Univer表格引擎:服务端公式计算与SDK集成实践 1. 从一张表格说起:为什么我要把 Univer 塞进 Node.js 里第一次接触 Univer 是在一个内部工具项目上。产品经理丢过来一个需求:能不能在后台管理系统里嵌入一个类似在线表格的编辑器,支持公式、多 Sheet、单元格样式,最好还能导出… · 2026/11/3 6:25:25
MySQL MVCC机制解析与高并发实战 1. MVCC基础概念:数据库的时光机机制MVCC(Multi-Version Concurrency Control)是MySQL实现高并发的核心技术之一。我第一次在线上系统遇到并发问题时,正是MVCC帮我解开了事务隔离的谜团。简单来说,它就像给数据库装上了… · 2026/11/3 6:25:25
EDID解析:显示器识别、DDC读取与HDMI扩展块实践 简介:这份文档面向显示器、显卡与嵌入式显示驱动方向的硬件及固件工程师,系统梳理扩展显示识别数据(EDID)的编程规范,帮助解决显示器与信号源之间识别失败、分辨率与刷新率不匹配等兼容性问题。全文以128字节基本数据块… · 2026/11/3 6:24:25
双极步进电机控制实战: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/2 13:10:28
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/3 6:04:24
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/3 5:52:46
STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
双极步进电机控制实战: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/2 13:10:28
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/3 6:04:24
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/3 5:52:46