Univer这个项目在开发者圈子里突然热起来最近不少人在讨论Univer在线表格怎么集成、能不能替代自研表格引擎。我自己从第一版开始就跟过这个开源项目从早期只有Sheet能力到后来扩展出Doc和Slide一路踩了不少坑也积累了不少经验。这篇东西不打算给你堆翻译文档而是想用真实项目的视角聊聊Univer是什么、为什么值得关注、怎么落到自己的业务里以及我在集成过程遇到的那些用文档查不出来的问题。1. Univer到底解决了谁的什么问题1.1 先搞清楚它和其他表格组件不是一个物种如果你之前用过类似x-spreadsheet、Handsontable这样的库第一眼看到Univer可能会觉得不就是又一个在线表格控件嘛。这个认知会害了你因为Univer在定位上和这类组件有本质区别。Univer是一个开源的Web办公基础设施底层是用TypeScript重写的核心能力不只是画一个格子面板而是把电子表格、文档、幻灯片这些办公能力做成了一套可插拔的框架。说得直白点别人给你的是一张画好了格子的画布Univer给你的是造画布的工作台和一套能让画布自我生长的机制。从使用目的上区分一下如果你只是想在页面上展示一个静态表格并且允许用户简单编辑那x-spreadsheet或者TuiGrid这类组件就够了。如果你的需求是我要做一个像Excel一样的在线表格并且将来可能要支持多人协同、复杂公式、透视表、还有各种自定义工具栏那Univer这种基础设施级别的东西才有意义。最近搜索热度里总带着Univer在线这个词我觉得大家真正关心的是这东西能不能在线跑起来当生产力工具。我可以直接回答能而且在线能力正是它最大的卖点。Univer天然就是为Web设计的不依赖任何桌面运行时浏览器打开即用前后端分离这套体系对它来说很自然。1.2 适合谁来用我把适合接入Univer的场景归纳成三类你可以对照看看自己的情况第一类是平台型产品比如低代码平台、数据可视化大屏、企业管理后台里面需要嵌一个让用户编辑数据的表格模块但又不想被厂商绑定。Univer开源且支持深度定制适合用来做成平台底层能力。第二类是在线协作工具的研发团队本身在做类似在线文档、在线表格的产品需要踩在巨人肩膀上不需要从零造轮子了。Univer的架构里带有协同设计的基础比拿普通表格组件去改出协同要靠谱得多。第三类是传统Excel数据密集型业务比如财务系统、ERP、供应链管理需要在浏览器里处理大量行数据同时又要兼容用户对Excel的操作习惯。Univer在行列性能、公式支持、样式处理上的完成度明显高过大多数自研方案。反过来如果你的需求只是导出几张表做个简单的填报页面那我劝你别上Univer杀鸡用牛刀除了把项目搞复杂没有任何好处。2. 核心机制拆解Canvas渲染、命令栈与插件生命周期2.1 为什么非要用Canvas渲染我见过不少团队在表格技术上翻车根源都是DOM渲染。一个100行×10列的网格要生成1000个DOM节点浏览器光维护节点就要卡掉半条命。Univer在渲染层走的是Canvas路线格子、内容、选区、边框全部在Canvas上调draw画出来的DOM层面只保留容器和必要的外壳结构。这样做的直接收益是渲染性能和节点数量解耦。你能滚动到底部渲染对象数量并不会随着数据行数线性爆炸。就实际体验来说在十万行级别的数据里滚动Univer仍然能保持比较流畅的帧率。这不是我用嘴吹的而是Canvas位图绘制天然的优势——浏览器只需要重绘变化的区域不需要反复做DOM diff。不过Canvas也带来了一个认知门槛你没法通过选中一个DOM元素然后改样式来定制单元格了。所有UI层面的定制都要走渲染器Renderer体系这个我在第4章会展开。2.2 命令模式带来的可扩展性和协同基础Univer把用户对工作簿的所有操作都抽象成了命令Command。点按钮、改单元格、插入行列、执行公式底层都是调用命令服务发出一个包含指令类型和参数的对象。为什么这样设计因为命令天然具备两个好处一是可回放。命令就是一条纯数据结构保存下来就可以在另一个客户端上重放这是协同编辑的核心前提。服务端拿到一条命令分发给其他在线用户所有终端执行同样的命令最终状态就一致了。二是可撤销重做。命令栈把正确命中和撤销命中的对偶关系管理起来撤销一个操作只需要执行它的反向操作。这一点比直接改数据状态的思路可靠得多我在自研阶段就吃过没有命令栈的亏数据被改乱了没法恢复。从二次开发角度命令模式意味着你不需要侵入源码去改内部逻辑。想加一个新功能比如把选中区域所有数字求和并显示在状态栏你只需要注册一个自定义命令它和官方命令一样参与撤销重做一样能被协同回放。这是所有深度定制的入口。2.3 插件从加载到销毁的生命周期Univer里的插件体系不是摆设而是整个框架的建筑结构。主要的开发模式就是装一个核心挂一堆插件每个插件负责一个独立能力域比如univerjs/sheets负责表格核心逻辑univerjs/sheets-ui负责表格界面渲染univerjs/formula负责公式计算。插件有明确的挂载和销毁钩子。我理解它的生命周期大致是插件注册进Univer实例框架调用插件的onMounted此时插件可以注册命令、菜单、快捷键、渲染器插件在onReady里访问已经就绪的资源页面卸载时调用dispose释放监听和资源我在React项目里遇到过一个典型问题组件热更新时Univer实例重复创建页面会白屏或者闪烁。这就是因为插件的销毁没有做干净。解决办法是显式调用univer.dispose()把实例彻底销毁而不是依赖垃圾回收。3. 快速集成从一个空白页到一个能编辑的工作簿3.1 安装依赖如果你现在从零开始我建议直接用univerjs/preset-sheets这个预设包它把Sheet相关的核心、UI、公式、剪贴板这些基础插件都打包好了省得你自己一个个去组合。npm install univer univerjs/preset-sheets或者用pnpmUniver这个项目对pnpm的支持更友好毕竟monorepo环境里符号链接能避免很多版本重复问题。pnpm add univer univerjs/preset-sheets3.2 初始化实例初始化代码不长但有几个设计点需要注意。我先给一个react版本的例子因为Univer配React是当前最主流的姿势。import { useEffect, useRef } from react; import { Univer } from univerjs/preset-sheets; import { LocaleType } from univerjs/core; function SpreadsheetApp() { const containerRef useRefHTMLDivElement(null); const univerRef useRefUniver | null(null); useEffect(() { if (!containerRef.current) return; const univer new Univer({ locale: LocaleType.ZH_CN, containers: [containerRef.current], // 这里可以传主题配置不传就是默认主题 }); univerRef.current univer; // 创建一个工作簿 univer.createUnit( { name: 数据填报, sheets: { sheet1: { cellData: { 0: { 0: { v: 项目, s: { b: true } }, 1: { v: 数量, s: { b: true } }, }, }, rowCount: 100, colCount: 20, defaultColumnWidth: 100, defaultRowHeight: 24, }, }, } ); return () { if (univerRef.current) { univerRef.current.dispose(); } }; }, []); return div ref{containerRef} style{{ width: 100%, height: 600px }} /; } export default SpreadsheetApp;这里有几个经验点分享第一container的高度一定要显式设置。Univer在初始化时要测量容器尺寸如果容器高度为0或者被父级隐藏你会发现页面一片空白控制台也没有报错看起来像加载失败。实际上就是测量了个寂寞。我习惯给包一层固定高度或者min-height的div。第二createUnit是核心API它决定了一个工作簿的初始结构。你可以在初始化时把后端拉取的数据以cellData的形式填充进去也可以后续用命令更新。3.3 加载已有Excel数据实际业务里基本不是从空表开始而是要打开已有的Excel数据。Univer本身不带读取xlsx文件的能力这一点需要注意。它和xlsx库搭配使用的时候流程是这样的用xlsx读取用户上传的文件得到JSON结构的数据把JSON的单元格数据映射成Univer的cellData结构用命令或直接createUnit初始化这个映射过程往往是最烦的。因为Excel的单元格合并、样式、数字格式在解析后会变成各种奇奇怪怪的结构眉毛胡子一把抓地塞进Univer反而会把界面搞崩。我的建议是优先只映射值和样式两个核心字段那些不必要的自定义属性不要保留合并单元格要用Univer的合并配置单独处理不能直接塞到单元格对象里数字格式字符串如果有最好原样传过去否则会出现日期显示成数字序列这种尴尬3.4 监听用户操作你要在集成页面感知用户改了哪些格子不能靠轮询DOM得走Univer的事件和命令监听。const commandService univer.__getInjectedPluginByName(univer.sheets) // 这里实际获取方式以你所用版本为准更推荐的是直接监听命令执行univer.getCommandService().onCommandExecuted((command) { // command 里包含命令类型和参数例如修改单元格值的命令 });从这里你可以拿到用户每一次实际发生的操作。我在做一个编辑痕迹系统时就是这么干的监听到命令后把命令对象交给后端保存协同的时候再下发到其他客户端执行。这就是Univer协同能力的地基后文还会再提到。4. 深度定制主题、右键菜单与公式扩展4.1 主题配置的核心思路业务方几乎都会提一个要求表格颜色要跟我们的品牌色一致。Univer默认主题虽然干净但不是万金油。好在它提供了主题配置入口主题本质上是色板变量的集合改主题就是覆盖这些变量。const univer new Univer({ locale: LocaleType.ZH_CN, containers: [containerRef.current], theme: { primaryColor: #2F6BFF, // 主色 textColor: #333333, // 文字颜色 borderColor: #E5E5E5, // 边框颜色 headerBackground: #F7F8FA, // 行列头背景 }, });要特别注意主题配置只影响部分UI外壳比如工具栏、行列头、选区的默认样式。如果你想要选中单元格之后高亮颜色换成粉色光配主题是做不到的这属于渲染器层面的定制需要走Renderer体系。这也是很多初次接触者搞混的地方。4.2 自定义一个按钮并执行自己的逻辑假设场景是给表格加一个统计选中区域的按钮点击之后在弹窗里显示平均值。我做这件事的方式是走命令注册不直接改UI组件源码。流程大概是注册一个自定义命令Dashboard.CalcSelectionStats在命令执行函数里拿到当前选区读取单元格数据计算平均值在工具栏注册一个按钮绑定命令按钮点击时发命令这样做的价值在于命令本身可以被撤销重做捕获也可以被协同回放。如果只是简单地把按钮click事件挂一个函数你的功能就游离在框架主逻辑之外将来协同或者命令行回放时这段操作会缺席。命令注册的伪代码思路import { CommandType } from univerjs/core; const calcCommand { id: dashboard.calc-stats, type: CommandType.MUTATION, handler: async (context, params) { // 1. 获取当前选区 // 2. 遍历单元格 // 3. 计算平均值 // 4. 更新UI展示 return { success: true }; }, }; univer.getCommandService().registerCommand(calcCommand);4.3 自定义单元格渲染器Canvas渲染模式下想给特定单元格画一个进度条、加一个图标、贴上状态标签这些都是通过自定义单元格渲染器实现的。Univer的渲染器注册机制允许你按单元格坐标或者范围自定义绘制逻辑。核心思路是你实现一个draw函数拿到Canvas绘制上下文和单元格的信息然后自己画内容。我记得自己第一次做回报表状态指示灯的时候就是在单元格里画一个圆点颜色表示状态这事情在DOM表格里很简单——塞个span改个背景色就行。但在Canvas表格里你得控制绘制坐标、内边距、圆点半径、颜色画完还想让选区正常框选还得处理命中测试的问题。经验总结就一句话尽量把自定义绘制限制在单元格内容层不要破坏框架的选区、边框、交互层。否则你画的图形会被选区高亮遮住或者反过来遮挡了文字。4.4 右键菜单扩展业务上还有一个很常见的需求右键菜单里加插入超链接标记异常之类的选项。Univer的右键菜单是挂在UI插件里的需要在插件生命周期里向菜单管理器注册条目。{ id: menu.custom-marker, title: 标记异常数据, icon: Icon.Warning, handler: () { /* 执行逻辑 */ }, }菜单条目的handler可以直接执行逻辑但更好的做法是上面说的把逻辑封装成命令菜单handler只负责发命令。5. 性能、协同与公式引擎真实业务场景能扛住吗5.1 大数据量下的表现取决于你的用法不少人对Univer有大数据性能无敌的想象我得泼一盆冷水它比DOM渲染的表格强很多但不是无限量的。Univer的Canvas渲染解决的是渲染层瓶颈但数据本身仍然存在内存里。如果你把50万行10列的数据全部塞进内存再叠加公式计算依赖关系内存占用会非常恐怖。我做过的压测里十万行纯文本数据初始化耗时在可接受范围内内存占用大概几百兆级别再多就需要考虑数据分页或者服务端过滤了。这个领域有个残酷的现实没有哪个纯前端表格能在UI上同时做到无限滚动、全量数据在线、公式联动实时更新、协同无顿挫。Univer已经做得算是均衡的但你在设计功能时还是要主动加一些约束比如限制可见数据量为最近10000行、支持按条件过滤再展示。5.2 协同编辑到底接什么Univer的架构为协同做了非常好的铺垫——命令流和快照模型天然适合传输和回放。但它没有内置一套协同后端也就是说需要你自己实现或者接一个协同服务。我理解的核心环节有两个一是快照Snapshot。Univer的工作簿状态可以序列化成快照相当于某一时刻的完整数据。新用户加入时下发一个快照给他让他快速初始化。二是命令Command。用户每次操作产生一个命令把命令以一定的顺序广播给其他在线终端其他终端执行命令同步状态。技术选型上你可以自己写WebSocket服务来转发命令更高级的可以接CRDT库比如Yjs来做冲突处理。但从我实际经验看大多数业务团队一开始根本不需要走到CRDT那一步。如果编辑人数少操作频率低先做命令顺序广播就已经能满足需求了。等用户量上来了模型自然会有冲突的问题出现那时候再引入OT操作转换或者CRDT也不迟。5.3 公式引擎不是花架子Univer的公式能力是它区别于一般表格组件的重要特征。它内置了数百个公式函数支持跨工作表引用也支持自定义函数。我最看重的是它具备异步公式能力。什么意思呢就是公式可以由外部数据驱动。举个例你在格子输入QUOTE(AAPL)可以通过自定义公式向你的行情服务发请求把股票价格拉回来填进表格。这种能力对金融、供应链、制造行业的业务系统很实用。注册自定义公式的骨架class QuoteFunction { evaluate(params, context) { // 向自己的后端请求行情数据 return latestPrice; } }注意公式引擎不是免费的午餐复杂公式链的联动计算会带来CPU消耗。如果一个sheet里有上万条带相互依赖的公式每次修改单元格都可能触发一大片重算。这种情况我做过的处理方案是把公式改为手动计算模式用户点一次算一次保住不卡顿才是第一位。6. 和市面上常见表格方案横向对比我按实际使用体验把Univer和几个常见方案放到一起比过。这里说的对比不是哪个好哪个坏而是哪种场景适合用哪种。方案渲染方式公式能力协同支持二次开发成本适合场景UniverCanvas强支持异步和自定义公式架构支持需自建后端中等插件体系完善在线办公产品、复杂表格系统HandsontableDOM基础公式支持需付费版本低API很直观简单编辑场景预算充足LuckysheetCanvasDOM混合有公式但生态一般有协同插件但不太活跃中等偏上需要快速做一个表格页x-spreadsheetCanvas公式很基础无原生协同低轻量展示和简单编辑TuiGridDOM基本无公式无原生协同低数据展示、后台表格列表这个表的结论挺明显的Univer的位置在想要做一个真正有生产力的在线表格这个档位其他几个要么不够深、要么协同需要商业版支撑。但含金量高意味着门槛也高。Univer的学习曲线比简单表格组件要陡。如果你团队里前端只有一两个人又没接触过Canvas渲染和命令模式这类概念前期投入成本要做好心理准备。我见过一个团队花了两周才把基础集成跑通原因是他们一直在用DOM表格的思路往Univer上套。7. 落地过程中的几个坑与我的处理办法7.1 热更新导致的白屏问题用Webpack或者Vite开发时代码一改动页面会刷新如果Univer实例没有正确销毁重新加载后容器里会残留旧的Canvas实例新实例又尝试初始化最终白屏。我的处理方案是在React组件的useEffect返回函数里显式调用univer.dispose()并且不要用React18严格模式的双重执行作为理由去跳过清理。严格模式下组件挂载两次如果清理函数写对了第二次挂载会得到全新的实例不会有冲突。另一个相关问题是容器重置。如果你在表格上方还有可折叠面板折叠时表格容器被父级折叠成0高度展开时Canvas可能没有重新测量表格会渲染异常。这时候可以调用Univer内部的布局刷新方法或者干脆在展开动作里强制重绘。7.2 版本之间的API变更Univer还在快速迭代期版本之间的API调整是常态。我踩过一个坑早期初始化方式是new UniverSheet(options)后来又统一成new Univer(options)然后通过工厂创建Unit。如果你在搜索引擎看到老文章照抄下来大概率报错。我的建议很实际以当前npm包内TypeScript类型定义为准优先使用preset-sheets它把版本之间不稳定的细节隐藏了一部分升级大版本前先跑一遍官方迁移指南不要锁死过老版本否则后面协同、公式、UI的bug修复你拿不到7.3 导出Excel时的格式丢失Univer本身能导入导出xlsx但做不到100%还原Excel的所有细节。图片、复杂图表、宏、条件格式的某些规则可能会在转换过程中丢失。我处理这个问题的策略是在产品里明确表格核心数据无损复杂对象可能降级显示同时在后端做一个转换服务的兜底。如果业务方非要100%还原说实话光靠前端开源库做不到厂商的付费SDK也未必完美。做好预期管理比技术攻关更重要。7.4 字体加载和中文渲染Canvas渲染的文字会在字体资源加载完成后重新排版。项目里如果字体切换不及时会出现文字位置串位或字体闪烁。我处理的办法是确保所需字体在Univer初始化之前就通过document.fonts.load加载完成或者使用系统字体栈避免加载远程字体的延迟。中文环境下还有一个经验不要给Canvas设置过大的字号像素值在动态缩放时可能出现边缘模糊dialpad这类高分屏设备上尤其明显。8. 从我自己的实践里总结几条选型铁律最后我不写那种总而言之的空话直接分享几条如果让我重新做一遍选型一定会优先守住的原则。第一先确定要不要协同再决定上不上Univer。如果只是内部后台单机编辑一张表Univer的价值会折损一大半此时换个轻量组件更划算。第二拿一个小而真实的需求做PoC比如导入某个真实的Excel文件、改两格数据、再导出。这个流程能跑通且性能能接受再决定铺开。我见过太多人架构还没跑通就开始铺业务最后全卡在基础能力上。第三把自定义逻辑全部封装成命令。哪怕一开始只有一个人在用表格也坚持这个规范。等将来要接协同、要做操作日志、要做撤销重做的时候你会发现这个约定救了你一命。第四给足容器高度做好实例销毁及时升级版本。这三件事是我见过最多的报障源头比什么高级API都重要。Univer是个非常有潜力的项目尤其在这个在线办公需求爆发的阶段。它站在了正确的技术基座上背后也有持续的社区投入。对于要在一张表格页上做出真正生产级体验的团队来说现阶段很难找到比它更合适的开源选择了。希望我这篇经验能帮你少走几步弯路。
企业数字化 ERP 产品动态
相关推荐
补码的本质是模运算:二进制有符号数的数学根基与硬件实现 简介:本资源是《计算机组成原理(第三版)》配套习题的完整参考答案,面向高校计算机类专业本科生及考研复习者,重点解决课后习题理解难、标准解法不明确、数值表示与系统结构概念易混淆等学习痛点。答案覆盖全书核心章节… · 2026/11/3 5:57:12
欧美汽车消费差异:小排量与大排量的文化技术对比 1. 欧洲与美国汽车消费差异现象解析走在欧洲街头,你会发现一个有趣的现象:道路上行驶的车辆普遍比美国小一圈,发动机排量也明显更小。这不是偶然的巧合,而是根植于两地不同汽车文化的必然结果。作为在汽车行业深耕多年的从业者&am… · 2026/11/3 5:57:12
鸿蒙UI开发:@Builder与@LocalBuilder构建器模式详解 1. 鸿蒙UI开发中的构建器模式解析在鸿蒙应用开发中,Builder和LocalBuilder是两种常用的轻量级UI元素构建方式。它们本质上都是ArkTS语言提供的装饰器,用于封装UI元素的构建逻辑,但在作用域和性能优化方面存在关键差异。1.1 构建器的基本概念构… · 2026/11/3 5:57:12
EDID解析:显示器识别、DDC读取与HDMI扩展块实践 简介:这份文档面向显示器、显卡与嵌入式显示驱动方向的硬件及固件工程师,系统梳理扩展显示识别数据(EDID)的编程规范,帮助解决显示器与信号源之间识别失败、分辨率与刷新率不匹配等兼容性问题。全文以128字节基本数据块… · 2026/11/3 6:24:25
回形针模拟器:用强化学习复现AI对齐与奖励黑客困境 1. 项目概述:从一枚回形针看AI对齐的经典难题我第一次看到“paperclip”这个词被当作项目名,心里就大概猜到了它指向的方向——回形针最大化器(Paperclip Maximizer),这是AI安全领域里最著名的思想实验之一。哲学家庄子… · 2026/11/3 6:24:25
企业勒索病毒防护与零损失恢复策略 1. 勒索病毒威胁现状与企业防护困境2026年爆发的SORRY勒索病毒已造成全国范围内超过2000家企业系统瘫痪。这种新型病毒采用RSA-4096与ChaCha20双重加密算法,能够绕过市面上90%的终端防护软件。根据网络安全应急中心监测数据,北京、上海、深圳三地企业受攻… · 2026/11/3 6:24:25
基于Hadoop的高校智能超市系统设计与实现 1. 项目背景与核心价值高校超市作为校园生活的重要基础设施,每天产生大量交易数据却鲜少被有效利用。传统超市管理系统仅能完成基础的商品进销存记录,无法实现销售预测、智能补货、个性化推荐等高级功能。这正是我们选择"基于Hadoop的高校智能化超市… · 2026/11/3 6:24:25
Git大文件管理:五大解决方案与最佳实践 1. 问题现象与根源分析当你执行git push命令时突然遇到"remote: error: File XXX exceeds 100MB"的报错,这种场景在开发大型二进制文件(如游戏资源、数据集、设计稿)时尤为常见。我去年为某影视特效团队解决过类似问题,… · 2026/11/3 6:24:25
Flink流处理引擎的数据一致性机制与实践 1. 流处理引擎的数据一致性挑战在分布式流处理系统中,数据一致性始终是架构设计的核心难题。以电商实时风控场景为例,当系统需要处理每秒百万级的交易事件时,如何确保欺诈检测结果的准确性?这就涉及到Flink作为流处理引擎提供的一… · 2026/11/3 6:23: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