ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

BlockNote 进阶表格实战:基于 onChange 事件实现带自动计算的表格列

BlockNote 进阶表格实战:基于 onChange 事件实现带自动计算的表格列 BlockNote 进阶表格实战基于 onChange 事件实现带自动计算的表格列【免费下载链接】BlockNoteA React Rich Text Editor thats block-based (Notion style) and extensible. Built on top of Prosemirror and Tiptap.项目地址: https://gitcode.com/gh_mirrors/bl/BlockNote本指南以 BlockNote 仓库中的进阶表格示例 17-advanced-tables-2 为蓝本讲解如何在 BlockNote 中开启表格高级特性单元格拆分/合并、单元格背景色、单元格文字颜色、表头行列并通过onChange事件监听表格内容变化实现数量 × 单价 小计、自动汇总总计Grand Total的实时计算表格。读完本文你将掌握 BlockNotetables配置项的完整用法、表格块table block的 JSON 数据结构以及如何安全地在事件回调中回写更新后的表格内容而不陷入循环更新。示例功能总览该示例实现了一张订单明细风格的表格完整功能清单如下自动计算Automatic Calculations每一行的Quantity × Price Total总计Grand Total自动计算所有小计之和并写入表格末行实时更新Real-time Updates修改数量或价格后计算结果立即刷新拆分/合并单元格Split cells可对单元格进行拆分与合并操作单元格背景色Cell background color支持给单个单元格着色单元格文字颜色Cell text color支持修改单元格内的文字颜色表头行列Table row and column headers使用表头提升表格的组织性与可读性。从示例的运行效果看App.tsx 中initialContent预置的表格这是一个 5 行 4 列的订单表首行为表头Item / Quantity / Price ($) / Total ($)中间 3 行为数据行末行为 Grand Total 汇总行。预置数据为 Laptop2 × 1200 2400、Mouse5 × 25 125、Keyboard3 × 80 240Grand Total 为 2765——这几个数字正是检验计算逻辑是否正确的现成基准。开启表格高级特性tables 配置项示例的核心前提是在创建编辑器时通过useCreateBlockNote的tables选项启用表格的高级功能const editor useCreateBlockNote({ // This enables the advanced table features tables: { splitCells: true, cellBackgroundColor: true, cellTextColor: true, headers: true, }, // ... });这四个开关在 BlockNoteEditor.ts 中有明确的官方定义与默认值配置项作用默认值splitCells是否允许在表格内拆分与合并单元格falsecellBackgroundColor是否允许修改单元格背景色falsecellTextColor是否允许修改单元格文字颜色falseheaders是否允许把单元格设置为表头false从源码可以看到编辑器构造函数会将这四个选项收敛到settings.tables中BlockNoteEditor.ts后续表格相关的 UI侧边菜单、单元格操作按钮等会据此决定是否渲染对应功能。因此不开启这些选项即使数据里带有colspan、backgroundColor等属性界面上的对应操作入口也不会出现。示例将四项全部置为true以获得完整的表格编辑体验。工作原理onChange 事件驱动计算示例没有使用自定义表格块而是复用 BlockNote 内置的table块在编辑器内容变化时通过onChange回调捕获变更并回写计算结果。整个工作流分为四步表格内容发生任何变化编辑单元格文字、增删行列等时BlockNoteView触发onChange从回调参数中调用getChanges()取出本次的变更列表changes遍历变更筛选出change.type update且change.block.type table的变更对命中的表格块调用calculateTableTotals重新计算再用editor.updateBlock将计算结果写回编辑器。onChange是 BlockNote 编辑器层的公开 API在 BlockNoteView.tsx 中作为组件 prop 透传语义与BlockNoteEditor.onChange一致回调签名包含编辑器实例以及可延迟求值的getChanges用于拿到变更后的块数据。之所以用getChanges()函数而非直接传对象是为了让使用者按需读取本次变更的详细信息如变更类型、涉及哪些块。核心监听代码来自 App.tsxBlockNoteView editor{editor} onChange{(editor, { getChanges }) { const changes getChanges(); if (changes.length 0 || applying.current) { return; } // prevents a double onChange because were updating the block here applying.current true; changes.forEach((change) { if (change.type update change.block.type table) { const updatedRows calculateTableTotals(change.block); if (updatedRows) { editor.updateBlock(change.block, { type: table, content: { ...change.block.content, rows: updatedRows, }, }); } } }); requestAnimationFrame(() (applying.current false)); }} /BlockNoteView两个值得注意的工程细节变更筛选change.type update表示块内容被更新change.block.type table确保只处理表格块避免对普通文本块的编辑也触发计算防循环回写editor.updateBlock写入表格后编辑器内容再次变化会再次触发onChange若不加保护将形成无限循环。示例用useRef(false)维护一个applying标志进入回写流程时置为true跳过后续回调并通过requestAnimationFrame在下一帧重置保证计算回写只生效一次。计算逻辑calculateTableTotals 逐行剖析calculateTableTotals接收一个table类型的块Block返回更新后的行数组。其处理规则如下App.tsx类型与行数守卫非table块直接返回rows.length 2至少需要表头 1 行数据时直接返回跳过特殊行第 0 行是表头最后一行是 Grand Total 行均不参与小计计算但最后一行会在后面单独更新汇总值提取单元格文本getCellText辅助函数兼容两种单元格形态——纯字符串或包含content[0].text的对象结构取不到数值时兜底为0计算小计quantity parseFloat(quantityText) || 0、price parseFloat(priceText) || 0total quantity * price并累加到grandTotal回写小计单元格把该行第 4 个单元格索引 3替换为带bold: true样式、绿色背景backgroundColor: green、白色文字的新tableCell内容为total.toString()条件标注若total 4000在商品名称后追加 (eligible for discount)标注示例中 Laptop 单价 1200、数量 2 时未达阈值此分支可用于验证更高金额场景更新总计行最后一行第 4 个单元格更新为grandTotal背景色为红色red、白色文字与绿色小计格形成视觉区分。数据行中每个单元格都是标准tableCell对象例如初始内容中的 Total 列{ type: tableCell, content: [{ type: text, text: 2400, styles: { bold: true } }], props: { colspan: 1, rowspan: 1, backgroundColor: green, textColor: white, textAlignment: center } }colspan/rowspan是表格块支持的核心结构属性其默认值均为 1。在 BlockNote 中表格块基于 prosemirror-tables 实现表头单元格与普通单元格分别映射为th/td节点见 blocks/Table/block.ts。跨行跨列会让单元格的逻辑坐标与物理坐标产生映射关系BlockNote 在 api/blockManipulation/tables/tables.ts 中专门处理相对/绝对索引的换算因此你在手动读写rows时务必保持colspan、rowspan与cells数组结构一致否则表格结构可能错乱。表格初始内容的 JSON 结构示例通过initialContent直接预置了完整表格这是理解表格数据模型的最佳入口。表格块的基本骨架为{ id: cbf287c6-770b-413a-bff5-ad490a0b562a, type: table, props: { textColor: default }, content: { type: tableContent, columnWidths: [150, 120, 120, 120], // 四列宽度像素 headerRows: 1, // 前 1 行作为表头 rows: [ /* row 对象数组 */ ], }, children: [], }关键字段说明columnWidths每列宽度数组长度需与列数一致示例为 4 列headerRows表头行数示例为 1即首行渲染为表头对应源码中的tableHeader节点与th标签rows行数组每行包含cells单元格数组单元格内是tableCell类型其content为内联内容文本props声明colspan、rowspan、backgroundColor、textColor、textAlignment。预置数据中已经演示了完整的样式用法表头单元格使用灰色背景gray加粗居中Total 列表头用蓝色背景白字数据行小计用绿色背景白字加粗Grand Total 行用黄色背景、最终汇总格用红色背景白字。这些backgroundColor/textColor的取值即来自tables.cellBackgroundColor/tables.cellTextColor开关所启用的样式能力。运行与调试该示例是标准的 Vite React 工程package.json依赖blocknote/core、blocknote/react、blocknote/mantine表格 UI 组件来自 Mantine 包装React 19 与 Vite 8。进入示例目录后执行npm install npm run dev # 启动开发服务器等价于 npm start生产构建与预览npm run build:prod # tsc 类型检查 vite build npm run preview # 本地预览构建产物调试建议修改任意数据行的 Quantity 或 Price 后观察 Total 列与 Grand Total 是否同步刷新——若未刷新检查是否误触发了applying.current保护例如连续快速输入时requestAnimationFrame尚未重置标志尝试合并两个单元格splitCells: true已开启后确认getCellText对合并单元格内容的提取仍然正确若需在表格外监听计算可改用编辑器实例的editor.onChangeAPI其回调同样提供getChanges()方便与其他业务逻辑如保存草稿、同步后端集成。小结本示例展示了 BlockNote 表格能力的两层用法配置层通过tables选项一次性开启单元格拆分/合并、背景色、文字颜色与表头四大特性逻辑层通过onChangegetChanges监听表格变更用updateBlock回写计算结果并借助 ref 标志规避回写造成的循环触发。这套事件监听—计算—回写的模式完全独立于表格 UI可直接迁移到报价单、库存表、预算表等任何需要公式化列计算的场景而对colspan/rowspan与tableContent数据结构的理解则是安全读写 BlockNote 表格数据的基础。【免费下载链接】BlockNoteA React Rich Text Editor thats block-based (Notion style) and extensible. Built on top of Prosemirror and Tiptap.项目地址: https://gitcode.com/gh_mirrors/bl/BlockNote创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表