电子表格这个东西几乎每个开发者都跟它打过交道。早些年做企业管理系统表格组件基本就是那几个老面孔功能能用但谈不上好用尤其是想往里面塞点自定义逻辑的时候那叫一个别扭。后来接触到Univer第一反应是这不就是个在线表格嘛但真正上手跑起来之后才发现它想做的事情比表面看到的要大得多——它是一套完整的、可嵌入的、插件化的表格与文档渲染引擎底层用 Canvas 做绘制上层用插件架构做能力拼装Node.js 环境下也能跑服务端渲染和计算。这篇文章就把我这一路折腾 Univer 的经验完整梳理一遍从它到底解决什么问题到环境怎么搭、核心 API 怎么用、插件怎么接、Canvas 渲染有哪些坑再到实际项目里怎么落地尽量讲透。1. Univer 到底在解决什么问题1.1 传统表格组件的三个死结先说清楚为什么会有 Univer 这类东西存在。做过前端表格的人应该都有体会市面上常见的表格方案大致分两类一类是基于 DOM 的表格组件另一类是基于 Canvas 的渲染引擎。前者上手快但数据量一上去就卡后者性能好但定制成本高、生态薄。DOM 表格的死结在于每一个单元格都是一个真实的 DOM 节点。你渲染一万行乘以二十列那就是二十万个节点浏览器直接跪。就算用虚拟滚动只渲染可视区域滚动时的节点回收和重建也会带来明显的抖动。更麻烦的是当你想要实现单元格内嵌图表公式实时计算多人协同编辑这类功能时DOM 表格的架构根本撑不住。Canvas 表格的死结则在于它把一切都画在画布上你没法用 CSS 去调样式没法用 DOM 事件去监听交互所有的点击、拖拽、输入都得自己算坐标、自己做命中检测。这对开发者来说门槛陡增。而 Univer 的思路是用 Canvas 做高性能渲染用插件架构做能力扩展用一套统一的文档模型把表格、文档、幻灯片都抽象成同一种东西。它不只是一个表格组件更像是一个办公套件的内核。1.2 Univer 的定位与核心能力从官方定位来看Univer 是一套可嵌入的、插件驱动的办公文档引擎。它的核心能力可以拆成几层来理解渲染层基于 Canvas 2D 的高性能渲染支持单元格、行列头、选区、滚动条、冻结窗格等完整表格视觉元素。数据层一套独立的文档模型Document Model把工作簿、工作表、单元格、公式、样式都抽象成可序列化的数据结构。计算层内置公式引擎支持常见的电子表格函数并且可以在 Web Worker 或 Node.js 中运行。插件层所有功能都以插件形式存在你可以按需加载也可以自己写插件扩展。协同层支持多人协同编辑的数据同步机制。这套架构带来的直接好处是你可以在一个 React 或者 Vue 项目里嵌入一个功能接近 Excel 的表格而且这个表格的行为完全由你控制。你也可以在 Node.js 服务端跑 Univer 的计算引擎做批量公式计算或者文档转换。1.3 谁适合用 Univer不是所有项目都适合上 Univer。如果你的需求只是展示一个几十行的静态表格那用原生 table 标签或者轻量组件就够了上 Univer 属于杀鸡用牛刀。但如果你遇到下面这些场景Univer 就值得认真考虑需要渲染十万级以上单元格且要求滚动流畅。需要实现类 Excel 的公式计算且计算逻辑要能跑在服务端。需要深度定制表格的交互和视觉现成组件改不动。需要把表格能力嵌入到自己的产品里而不是跳转到第三方页面。需要多人协同编辑同一份表格数据。我自己的项目是一个数据看板平台用户需要在浏览器里直接编辑几十万行的数据表还要支持公式列和条件格式。试过几个方案之后最终选了 Univer主要就是看中它的 Canvas 渲染性能和插件化架构。2. 环境搭建从零跑通第一个 Univer 实例2.1 Node.js 环境的准备与版本选择Univer 的开发环境依赖 Node.js这一点跟大多数现代前端项目一样。但这里有个容易被忽略的细节Node.js 的版本选择会直接影响依赖安装的成功率。我实测下来Node.js 18.20.4 LTS 和 20.x LTS 都是比较稳的选择。22.x 虽然也能跑但部分依赖包的预编译二进制可能还没跟上偶尔会遇到 node-gyp 编译报错。如果你用的是 CentOS 7.9 这类老系统系统自带的 Node.js 版本往往太低需要手动升级。安装步骤本身不复杂但有几个坑要提前说# 查看当前 Node.js 版本 node -v # 如果版本过低建议用 nvm 管理多版本 curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash source ~/.bashrc nvm install 18.20.4 nvm use 18.20.4提示在 CentOS 7.9 上安装时如果遇到 GLIBC 版本不兼容的问题不要硬升级系统库直接用 nvm 安装预编译版本更稳妥。安装完成后验证一下 npm 是否正常node -v # 应输出 v18.20.4 npm -v # 应输出对应版本号2.2 创建项目并安装 Univer 依赖Univer 的包结构是拆分的核心包加上各种插件包。新手最容易犯的错是只装了核心包结果发现表格渲染不出来——因为渲染能力本身也是插件。一个最小可运行的表格实例需要装这些包npm install univerjs/core univerjs/design univerjs/docs univerjs/docs-ui \ univerjs/engine-formula univerjs/engine-render univerjs/sheets \ univerjs/sheets-formula univerjs/sheets-ui univerjs/ui这里解释一下每个包的作用方便你按需取舍包名作用是否必需univerjs/core核心文档模型与插件系统必需univerjs/engine-renderCanvas 渲染引擎必需univerjs/sheets表格数据模型必需univerjs/sheets-ui表格 UI 交互必需univerjs/ui通用 UI 组件必需univerjs/engine-formula公式计算引擎按需univerjs/sheets-formula表格公式集成按需univerjs/design设计系统与样式按需2.3 初始化 Univer 实例的完整代码装完依赖之后初始化代码是第一个真正的门槛。Univer 的初始化流程是创建实例 → 注册插件 → 配置 → 渲染顺序不能乱。import { Univer, LocaleType, merge } from univerjs/core; import { UniverRenderEnginePlugin } from univerjs/engine-render; import { UniverFormulaEnginePlugin } from univerjs/engine-formula; import { UniverUIPlugin } from univerjs/ui; import { UniverSheetsPlugin } from univerjs/sheets; import { UniverSheetsUIPlugin } from univerjs/sheets-ui; import { UniverSheetsFormulaPlugin } from univerjs/sheets-formula; // 中文语言包 import DesignZhCN from univerjs/design/locale/zh-CN; import UIZhCN from univerjs/ui/locale/zh-CN; import SheetsZhCN from univerjs/sheets/locale/zh-CN; import SheetsUIZhCN from univerjs/sheets-ui/locale/zh-CN; const univer new Univer({ locale: LocaleType.ZH_CN, locales: { [LocaleType.ZH_CN]: merge( {}, DesignZhCN, UIZhCN, SheetsZhCN, SheetsUIZhCN ), }, }); // 注册插件顺序有讲究 univer.registerPlugin(UniverRenderEnginePlugin); univer.registerPlugin(UniverFormulaEnginePlugin); univer.registerPlugin(UniverUIPlugin, { container: app, header: true, footer: true, }); univer.registerPlugin(UniverSheetsPlugin); univer.registerPlugin(UniverSheetsUIPlugin); univer.registerPlugin(UniverSheetsFormulaPlugin); // 创建工作簿 univer.createUnit(UniverInstanceType.UNIVER_SHEET, { id: workbook-01, sheetOrder: [sheet-01], sheets: { sheet-01: { id: sheet-01, name: 数据表, rowCount: 1000, columnCount: 26, cellData: { 0: { 0: { v: 产品名称 }, 1: { v: 销量 }, 2: { v: 单价 }, }, 1: { 0: { v: A产品 }, 1: { v: 1200 }, 2: { v: 35.5 }, }, }, }, }, });这段代码跑起来页面上就会出现一个带工具栏的表格。但这里有几个我踩过的坑必须提醒第一个坑是容器 ID。container参数填的是 DOM 元素的 id不是选择器。如果你写#app或者.app它会找不到元素表格直接不渲染控制台也不一定报错。第二个坑是插件注册顺序。渲染引擎必须在 UI 插件之前注册否则 UI 插件初始化时找不到渲染上下文。这个顺序在官方文档里没有特别强调但实测下来顺序错了就是白屏。第三个坑是语言包。如果你不注册语言包界面上的按钮文字会显示成 key 而不是中文看起来像 bug其实是缺 locale。2.4 在 React 项目中的集成方式Univer 本身不绑定框架但在 React 里集成需要处理生命周期。核心原则是Univer 实例只创建一次组件卸载时要销毁。import { useEffect, useRef } from react; import { Univer } from univerjs/core; function UniverSheet() { const containerRef useRef(null); const univerRef useRef(null); useEffect(() { if (!containerRef.current) return; const univer new Univer({ /* 配置 */ }); // ... 注册插件 univerRef.current univer; return () { univer.dispose(); univerRef.current null; }; }, []); return div ref{containerRef} style{{ width: 100%, height: 600px }} /; }这里的关键是univer.dispose()。如果不调用Canvas 的事件监听和定时器不会释放在单页应用里反复切换路由会导致内存泄漏。我一开始没注意这个切了十几次页面之后浏览器直接卡死。3. Canvas 渲染引擎的工作机制与性能边界3.1 为什么 Univer 选择 Canvas 而不是 DOM这个问题值得单独讲因为它决定了 Univer 的很多设计取舍。DOM 渲染表格的优势是天然支持 CSS、天然支持无障碍、天然支持文本选择。但它的劣势在数据量大时是致命的。Canvas 渲染的核心优势是绘制成本与单元格数量解耦。不管你有一千个单元格还是一百万个单元格Canvas 每一帧只绘制可视区域内的内容。滚动的时候只需要重新计算可视区域的偏移量然后重绘不需要创建和销毁 DOM 节点。Univer 的渲染引擎在这一点上做了几层优化分层渲染把背景、网格线、单元格内容、选区、滚动条分成不同的层各自独立重绘。滚动时只重绘内容层网格线和背景层不动。脏矩形重绘只重绘发生变化的区域而不是整块画布。离屏缓存把不常变化的内容缓存成离屏 Canvas需要时直接贴图。这些优化叠加起来让 Univer 在渲染十万级单元格时依然能保持 60fps 的滚动帧率。我实测过一个 5000 行 × 50 列的工作表滚动基本无感。3.2 渲染引擎的核心对象模型理解 Univer 的渲染需要搞清楚几个核心对象的关系Scene场景是整个渲染的根容器管理所有图层。Layer图层每个图层是一块独立的 Canvas。Viewport视口负责坐标转换把文档坐标映射到屏幕坐标。Shape图形是渲染的基本单元单元格、文字、边框都是 Shape。当你滚动表格时实际发生的是 Viewport 的偏移量变化然后 Scene 根据新的偏移量重新计算哪些 Shape 需要绘制。这个过程中Shape 对象本身是不变的变的只是它们的屏幕坐标。这个模型的好处是你可以直接操作 Scene 来添加自定义的渲染内容。比如你想在表格上叠加一个水印可以往 Scene 里加一个自定义 Layer画上水印文字它就会一直浮在表格上方。3.3 自定义渲染内容的实操方法假设我们要在表格的某个单元格上画一个红色角标标记这行数据有异常。用 Univer 的渲染 API 可以这样实现import { SheetSkeletonManagerService } from univerjs/sheets-ui; // 获取当前工作表的骨架管理器 const skeletonManager univer.__getInjector() .get(SheetSkeletonManagerService); const skeleton skeletonManager.getCurrentSkeleton(); const scene skeleton.scene; // 创建一个自定义图层 const layer scene.getLayer(custom-marker-layer) || scene.createLayer(custom-marker-layer, 100); // 在指定单元格位置绘制角标 const cellInfo skeleton.getCellByIndex(5, 2); // 第6行第3列 layer.drawRect(cellInfo.startX cellInfo.width - 8, cellInfo.startY, 8, 8, { fill: #ff4d4f, });这段代码的关键在于getCellByIndex它能把行列索引转换成屏幕坐标。这个转换依赖 Skeleton而 Skeleton 是 Univer 根据当前滚动位置和缩放比例动态计算的。注意自定义图层的内容不会自动跟随表格滚动你需要在滚动事件里手动更新坐标或者把图层挂到 Scene 的滚动容器下。这一点官方文档讲得比较含糊我是看源码才搞明白的。3.4 Canvas 渲染的常见问题与排查用 Canvas 渲染表格有几个问题是必然会遇到的问题一文字模糊。Canvas 在高分屏上如果不做处理文字会发虚。解决办法是根据window.devicePixelRatio调整 Canvas 的实际像素尺寸然后缩放上下文。const dpr window.devicePixelRatio || 1; canvas.width width * dpr; canvas.height height * dpr; canvas.style.width width px; canvas.style.height height px; ctx.scale(dpr, dpr);Univer 内部已经处理了这个问题但如果你自己往 Scene 里加内容要注意坐标是按逻辑像素算的不要重复缩放。问题二导出白图。这个在移动端 Safari 上特别常见。当你用canvas.toDataURL()导出时如果 Canvas 是跨域的或者绘制过程中有异步操作没完成导出的就是白图。解决办法是确保所有绘制操作同步完成并且图片资源都设置了crossOrigin。问题三滚动卡顿。如果自定义渲染内容太多或者每帧都做大量计算滚动就会掉帧。原则是能在初始化时算好的不要放到渲染循环里。4. 插件架构Univer 真正的扩展点4.1 插件系统的设计哲学Univer 的插件架构是它区别于普通表格组件的地方。整个引擎的能力都是通过插件拼装出来的核心只提供最基础的文档模型和插件容器。这种设计的好处是按需加载。你不需要公式就不装公式插件打包体积就小。你需要自定义功能就写一个插件注册进去它就能访问核心的所有能力。插件的生命周期大致是注册 → 依赖注入 → 初始化 → 运行 → 销毁。每个插件可以声明自己依赖哪些服务Univer 的依赖注入容器会自动解析。4.2 写一个最小可用的自定义插件假设我们要加一个功能点击工具栏按钮把当前选中区域的所有数字乘以 2。这个功能需要访问表格数据、选区信息和 UI 注册能力。import { Plugin, Inject, CommandType } from univerjs/core; import { ISelectionManager } from univerjs/sheets-ui; import { ICommandService } from univerjs/core; class DoubleValuePlugin extends Plugin { static pluginName DoubleValuePlugin; Inject(ISelectionManager) private _selectionManager; Inject(ICommandService) private _commandService; onStarting() { // 注册一个命令 this._commandService.registerCommand({ id: double-value, type: CommandType.COMMAND, handler: (accessor, params) { const selection this._selectionManager.getCurrentSelection(); if (!selection) return false; // 遍历选中区域把值乘以2 // ... 具体的数据操作逻辑 return true; }, }); } } univer.registerPlugin(DoubleValuePlugin);这个插件注册之后你就可以通过命令服务触发它。真正的数据修改需要通过 Univer 的 Mutation 机制而不是直接改数据这样才能保证撤销重做和协同同步正常工作。4.3 插件之间的通信与依赖管理插件之间不能直接互相引用必须通过依赖注入。这是为了保证插件可以独立加载和卸载。Univer 的注入系统基于装饰器Inject声明依赖容器负责解析。如果依赖的服务还没注册插件初始化就会失败。所以插件注册顺序很重要被依赖的插件要先注册。我遇到过一个典型问题自定义插件里想用公式引擎的能力但公式插件还没注册结果注入失败。解决办法是把自定义插件的注册放到公式插件之后。4.4 插件化带来的打包与加载策略插件化架构对打包策略有直接影响。因为每个插件是独立的包你可以做动态导入只在需要的时候加载。// 按需加载公式插件 if (needFormula) { const { UniverFormulaEnginePlugin } await import(univerjs/engine-formula); univer.registerPlugin(UniverFormulaEnginePlugin); }这样首屏只需要加载核心和基础表格插件公式、图表这些重能力可以延迟加载。对于一个数据看板产品来说这个优化能显著降低首屏时间。5. 公式引擎与服务端计算5.1 公式引擎的独立运行能力Univer 的公式引擎是可以脱离 UI 独立运行的。这意味着你可以在 Node.js 服务端加载一个工作簿数据执行公式计算然后返回结果。这个能力在很多场景下非常有用比如批量生成报表、做数据校验、实现服务端的数据透视。服务端运行公式引擎的基本流程是创建 Univer 实例 → 注册公式引擎插件 → 加载工作簿数据 → 触发计算 → 读取结果。const { Univer, UniverInstanceType } require(univerjs/core); const { UniverFormulaEnginePlugin } require(univerjs/engine-formula); const { UniverSheetsPlugin } require(univerjs/sheets); const univer new Univer(); univer.registerPlugin(UniverFormulaEnginePlugin); univer.registerPlugin(UniverSheetsPlugin); const workbook univer.createUnit(UniverInstanceType.UNIVER_SHEET, { // ... 工作簿数据包含公式 }); // 触发计算 const sheet workbook.getActiveSheet(); const cellValue sheet.getCell(0, 0).getValue();5.2 公式计算的性能考量公式计算是 CPU 密集型操作。如果工作簿里有大量复杂公式计算可能会阻塞主线程。Univer 的解决方案是把计算放到 Web Worker 里。在浏览器端公式引擎插件会自动使用 Worker。但在 Node.js 端因为没有 Worker 的概念计算是同步的。如果你在服务端处理大工作簿要注意加超时控制和分批处理。我实测过一个包含五千个 VLOOKUP 公式的工作簿在 Node.js 里完整计算一次大约需要 800 毫秒。如果并发请求多这个耗时会累积。所以服务端计算建议做结果缓存相同输入直接返回缓存结果。5.3 自定义公式函数的注册Univer 的公式引擎支持注册自定义函数。这在业务系统里很有用比如你需要一个函数去查数据库或者调用内部 API。import { IFunctionService } from univerjs/engine-formula; class CustomFunctionPlugin extends Plugin { Inject(IFunctionService) private _functionService; onStarting() { this._functionService.registerFunction({ name: MY_CUSTOM_FUNC, calculate: (args) { // 自定义计算逻辑 return args[0] * 2 args[1]; }, }); } }注册之后用户在单元格里输入MY_CUSTOM_FUNC(1, 2)就能调用。需要注意的是自定义函数的计算必须是纯函数不能有副作用否则在协同场景下会出现数据不一致。6. 实际项目落地中的经验与避坑6.1 大数据量场景下的内存控制Univer 虽然渲染性能好但数据模型本身是存在内存里的。如果你加载一个百万行的工作簿内存占用会非常可观。我的经验是按需加载不要一次性把所有数据塞进工作簿而是分页或者分片加载。及时释放切换工作簿时调用dispose()释放旧实例。避免冗余数据cellData 里只存有值的单元格空单元格不要占位。我做过一个测试一个 10000 行 × 100 列、每格都有数据的工作簿内存占用大约在 200MB 左右。如果数据量再大就要考虑虚拟化加载了。6.2 与后端数据同步的时机选择Univer 的数据修改是通过 Mutation 机制走的每次修改都会产生一个 Mutation 对象。你可以监听这些 Mutation把它们同步到后端。但这里有个时机问题如果每次修改都立即同步网络请求会非常频繁。如果攒一批再同步又可能丢数据。我的做法是防抖 批量提交用户停止操作 500 毫秒后把这段时间内的所有 Mutation 打包发到后端。let pendingMutations []; let syncTimer null; univer.onMutation((mutation) { pendingMutations.push(mutation); clearTimeout(syncTimer); syncTimer setTimeout(() { syncToServer(pendingMutations); pendingMutations []; }, 500); });6.3 移动端适配的注意事项Univer 在移动端的表现和桌面端有差异。主要问题是触摸事件的处理和虚拟键盘的弹出。在 iOS Safari 上Canvas 的触摸事件和滚动行为需要特别处理。如果表格区域可以滚动要确保touch-action设置正确否则会出现页面整体滚动而不是表格内部滚动的情况。另外移动端的虚拟键盘弹出时会改变视口高度导致 Canvas 尺寸变化。如果不监听resize事件重新调整表格会显示错位。6.4 常见报错与排查思路最后整理几个我遇到过的报错和排查方法报错现象可能原因排查方向表格白屏不渲染容器 ID 错误或插件顺序不对检查 container 参数和插件注册顺序按钮文字显示为 key语言包未注册检查 locales 配置公式不计算公式插件未注册或未触发计算检查插件注册和计算触发时机滚动卡顿自定义渲染内容过多检查自定义 Layer 的绘制逻辑内存持续增长实例未销毁检查组件卸载时是否调用 dispose导出图片为空白跨域或异步绘制未完成检查图片 crossOrigin 和绘制时序排查 Univer 问题的通用思路是先看控制台有没有报错再看插件是否都注册了然后检查数据格式是否符合文档模型的要求。大部分问题都出在这三个环节。7. 我对 Univer 的一些个人判断用了一段时间 Univer整体感受是它的架构设计确实比传统表格组件高一个层次但生态和文档还在完善中。有些 API 需要看源码才能搞明白官方示例覆盖的场景也有限。如果你打算在项目里用它我的建议是先花时间把插件架构和渲染模型搞清楚这两个是理解一切的基础。然后从一个最小实例开始逐步加插件每加一个就验证一下不要一次性把所有插件都装上。遇到问题优先看源码Univer 的代码结构还是比较清晰的核心逻辑都能找到。另外Univer 的版本迭代比较快不同版本之间的 API 可能有变化。锁定一个稳定版本不要盲目升级升级前先看 changelog。我在项目里就遇到过升级之后插件注册方式变了的情况排查了半天才发现是版本问题。对于服务端计算场景建议做好超时和缓存不要把它当成实时的计算服务来用。对于前端渲染场景注意内存管理和实例销毁单页应用里尤其重要。
企业数字化 ERP 产品动态
相关推荐
X-XSS-Protection 废弃后,XSS 防护该靠什么? 第一次认真研究 X-XSS-Protection 这个响应头,是因为一份外部扫描报告。报告里有一条低危告警写着“响应缺少 X-XSS-Protection 头,可能存在 XSS 风险”,而站点其实已经有比较完整的输出编码规范了。我盯着那条告警想了很久:这个头… · 2026/11/3 15:01:20
企业知识管理系统(KMS)的核心功能与落地实践 1. 知识管理系统的时代价值十年前我刚入行时,团队还在用共享文件夹管理项目文档,重要信息散落在各种邮件和聊天记录里。直到参与了一个跨国协作项目,才真正体会到知识管理系统(KMS)的价值。当时我们团队分布在三个时区… · 2026/11/3 15:01:20
【java虚拟机】JVM知识框架快速一览 /* 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 18:20:00
【大模型应用开发极简入门】提示工程二:零样本学习、少样本学习与改善提示效果 /* 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 18:20:00
【高等数学】第三章知识点(2)一元函数积分:定积分与反常积分、与几何应用 /* 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 18:20:00
【python虚拟环境管理】【mac m3】使用poetry管理python项目 /* 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 18:20:00
TabPFN-2.6案例研究:在真实世界表格数据上的10个成功应用 TabPFN-2.6案例研究:在真实世界表格数据上的10个成功应用 【免费下载链接】tabpfn_2_6 项目地址: https://ai.gitcode.com/hf_mirrors/Prior-Labs/tabpfn_2_6
TabPFN-2.6是一款革命性的表格预测基础模型,它通过上下文学习在单次前向传播中解决表… · 2026/11/3 18:18: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
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