
前端UI组件【免费下载链接】ceJspreadsheet is a lightweight JavaScript data grid component for creating interactive data grids with advanced spreadsheet controls.项目地址https://gitcode.com/gh_mirrors/ce/ce点击查看免费下载Jspreadsheet 是一款轻量级的 JavaScript 数据网格组件其 v3 版本内置了一套覆盖面极广的事件系统可对数据变更、行列操作、选择、排序、粘贴、编辑、样式等几乎所有交互进行监听与拦截。本文以官方 v3 文档docs/jspreadsheet/v3/docs/events.md为骨架结合仓库源码与官方示例events.md 示例、table-scripting.md 示例系统讲解每个事件的触发时机、回调签名、返回值约定并深入剖析事件分发机制的底层实现帮助你基于事件驱动完成数据联动、日志追踪、图表刷新等实战集成。一、事件总览一张表掌握全部回调Jspreadsheet v3 将几乎所有用户交互都暴露为配置对象中的回调函数。在初始化时把这些函数以onxxx: function(...)的形式传入构造配置即可完成绑定。完整事件清单如下摘自 v3 官方文档事件说明onload当setData被调用、数据加载完成后触发onbeforechange列值被修改之前触发。v3.4.0 起支持在该方法中返回一个新值可覆盖原始值onchange列值被修改之后触发onafterchanges表格中所有变更全部应用完成之后触发onpaste粘贴动作执行完成后触发onbeforepaste粘贴动作执行之前触发用于解析输入数据应返回处理后的数据oninsertrow新行插入之后触发onbeforeinsertrow新行插入之前触发返回false可取消插入ondeleterow行被删除之后触发onbeforedeleterow行被删除之前触发返回false可取消删除oninsertcolumn新列插入之后触发onbeforeinsertcolumn新列插入之前触发返回false可取消插入ondeletecolumn列被删除之后触发onbeforedeletecolumn列被删除之前触发返回false可取消删除onmoverow行被移动到新位置之后触发onmovecolumn列被移动到新位置之后触发onresizerow行高发生变化之后触发onresizecolumn列宽发生变化之后触发onselection选区发生变化时触发onsort列被排序之后触发onfocus表格获得焦点时触发onblur表格失去焦点时触发onmerge列发生合并时触发onchangeheader表头被修改时触发onundo执行撤销undo时触发onredo执行重做redo时触发oneditionstart调用openEditor打开编辑器时触发oneditionend调用closeEditor关闭编辑器时触发onchangestyle调用setStyle改变单元格样式时触发onchangemeta调用setMeta改变元数据时触发从事件命名可以归纳出两条清晰规律before / after 成对出现onbeforexxx在动作执行前触发可用于拦截或改写onxxx在动作执行后触发适合做结果响应。返回值的特殊约定onbeforechange返回新值可覆盖原值onbeforepaste返回处理后的数据onbeforeinsertrow、onbeforedeleterow、onbeforeinsertcolumn、onbeforedeletecolumn返回false可取消对应操作。二、表格脚本定制updateTable 动态改写渲染结果除了事件回调v3 还提供了原生updateTable方法允许你在每次表格刷新时按单元格定制展示内容实现展示层的动态脚本化而无需改动底层数据。该方法在数据更新、行列插入后由内部统一调用现代版本源码中位于 src/utils/internal.js#L13 的updateTable负责处理minSpareRows/minSpareCols补行补列、页脚刷新、角标位置更新等收尾工作随后setValue/setValueFromCoords会触发onafterchanges见 src/utils/data.js#L272-L284。官方表格脚本示例完整可运行代码见 docs/jspreadsheet/v3/examples/table-scripting.md展示了updateTable的三类典型用法——数字格式化、斑马纹行着色、合计行高亮html script srchttps://bossanova.uk/jspreadsheet/v3/jexcel.js/script script srchttps://jsuites.net/v3/jsuites.js/script link relstylesheet hrefhttps://bossanova.uk/jspreadsheet/v3/jexcel.css typetext/css / link relstylesheet hrefhttps://jsuites.net/v3/jsuites.css typetext/css / script srchttps://cdnjs.cloudflare.com/ajax/libs/numeral.js/2.0.6/numeral.min.js/script div idspreasheet2/div script let table2 jexcel(document.getElementById(spreasheet2), { data: [ [BR, Cheese, 1, 3.99], [CA, Apples, 0, 1.00], [US, Carrots, 1, 0.90], [GB, Oranges, 0, 1.20], [CH, Chocolats, 1, 0.40], [AR, Apples, 1, 1.10], [AR, Bananas, 1, 0.30], [BR, Oranges, 1, 0.95], [BR, Pears, 1, 0.90], [, , , ROUND(SUM(D1:D8), 2)], ], columnSorting:false, columns: [ { type: autocomplete, title: Country, width: 250, source: [BR, CA, US, UK, AR, CH, GB] }, { type: autocomplete, title:Food, width:150, source: [Apples,Bananas,Carrots,Oranges,Cheese,Kiwi,Chocolats,Pears] }, { type: checkbox, title:Stock, width:100 }, { type: number, title:Price, width:100 }, ], updateTable:function(instance, cell, col, row, val, label, cellName) { // 1. 对第 4 列Price做货币格式化仅改写显示文本不改动数据 if (col 3) { txt cell.innerText; cell.innerHTML jSuites.mask.render(txt, { mask: $ 0.00 }); } // 2. 奇数行使用浅蓝背景形成斑马纹 if (row % 2) { cell.style.backgroundColor #edf3ff; } // 3. 合计行第 10 行索引 9清除前 3 列内容、写入 Total、整体反白高亮 if (row 9) { if (col 3) { cell.innerHTML ; } if (col 2) { cell.innerHTML Total; cell.style.fontWeight bold; } cell.className ; cell.style.backgroundColor #f46e42; cell.style.color #ffffff; } } }); /script /htmlupdateTable回调签名包含 7 个参数参数含义instance当前表格实例jexcel 对象cell当前单元格 DOM 元素col列索引从 0 开始row行索引从 0 开始val当前单元格的值label单元格的显示标签cellName单元格名称如A1由于updateTable是逐单元格回调你可以在其中按col/row坐标组合出任意渲染规则。注意示例中第 9 行清空cell.className并覆盖背景色说明该回调发生在样式渲染之后属于最终展示层的二次加工非常适合做报表类展示场景。三、实战示例一绑定全套跟踪事件官方 events 示例完整代码见 docs/jspreadsheet/v3/examples/events.md演示了如何把大部分事件一次性绑定到表格上并把每次触发追加到页面日志区——这是理解事件何时触发、回调带什么参数的最快方式html script srchttps://bossanova.uk/jspreadsheet/v3/jexcel.js/script script srchttps://jsuites.net/v3/jsuites.js/script link relstylesheet hrefhttps://bossanova.uk/jspreadsheet/v3/jexcel.css typetext/css / link relstylesheet hrefhttps://jsuites.net/v3/jsuites.css typetext/css / div idspreadsheet/div div idlog/div script let log document.getElementById(log); const changed function(instance, cell, x, y, value) { let cellName jexcel.getColumnNameFromId([x,y]); log.append( - New change on cell cellName to: value ); } const beforeChange function(instance, cell, x, y, value) { let cellName jexcel.getColumnNameFromId([x,y]); log.append( - The cell cellName will be changed); } const insertedRow function(instance) { log.append( - Row added); } const insertedColumn function(instance) { log.append( - Column added); } const deletedRow function(instance) { log.append( - Row deleted); } const deletedColumn function(instance) { log.append( - Column deleted); } const sort function(instance, cellNum, order) { order (order) ? desc : asc; log.append( - The column cellNum sorted by order ); } const resizeColumn function(instance, cell, width) { log.append( - The column cell resized to width width px); } const resizeRow function(instance, cell, height) { log.append( - The row cell resized to height height px); } const selectionActive function(instance, x1, y1, x2, y2, origin) { let cellName1 jexcel.getColumnNameFromId([x1, y1]); let cellName2 jexcel.getColumnNameFromId([x2, y2]); log.append( - Selection from cellName1 to cellName2 ); } const loaded function(instance) { log.append( - New data is loaded); } const moveRow function(instance, from, to) { log.append( - The row from was move to the position of to ); } const moveColumn function(instance, from, to) { log.append( - The col from was move to the position of to ); } const blur function(instance) { log.append( - The table is blur); } const focus function(instance) { console.log(instance) log.append( - The table is focus); } jexcel(document.getElementById(spreadsheet), { data: [ [Mazda, 2001, 2000, 2006-01-01], [Peugeot, 2010, 5000, 2005-01-01], [Honda Fit, 2009, 3000, 2004-01-01], [Honda CRV, 2010, 6000, 2003-01-01], ], rowResize:true, columnDrag:true, columns: [ { type: text, width:200 }, { type: text, width:100 }, { type: text, width:100 }, { type: calendar, width:100 }, ], onchange: changed, onbeforechange: beforeChange, oninsertrow: insertedRow, oninsertcolumn: insertedColumn, ondeleterow: deletedRow, ondeletecolumn: deletedColumn, onselection: selectionActive, onsort: sort, onresizerow: resizeRow, onresizecolumn: resizeColumn, onmoverow: moveRow, onmovecolumn: moveColumn, onload: loaded, onblur: blur, onfocus: focus, }); /script /html3.1 从示例中读取回调签名该示例直接暴露了 v3 各事件的回调参数以instance为第一个参数、随后是事件相关坐标/数值的通用约定onchange(instance, cell, x, y, value)cell是单元格 DOM 元素x/y是列/行索引value是新值。示例用jexcel.getColumnNameFromId([x, y])把坐标换算成A1形式的单元格名称。onbeforechange(instance, cell, x, y, value)与onchange签名一致但发生在写入之前。onsort(instance, cellNum, order)order为0升序或1降序示例中以三元表达式转成asc/desc输出。onresizecolumn(instance, cell, width)/onresizerow(instance, cell, height)携带调整后的像素值。onselection(instance, x1, y1, x2, y2, origin)x1/y1为选区起点、x2/y2为选区终点origin为选区来源。onmoverow(instance, from, to)/onmovecolumn(instance, from, to)携带原位置与新位置索引。oninsertrow、oninsertcolumn、ondeleterow、ondeletecolumn、onload、onfocus、onblur通常只接收instance一个参数。提示示例中开启了rowResize: true与columnDrag: true这两个配置是onresizerow、onresizecolumn、onmoverow、onmovecolumn事件能够被触发的前提绑定事件时请确认对应交互配置已打开。3.2 事件顺序从 onbeforechange 到 onafterchanges通过编辑一个单元格这一最基础的操作可以串联出事件的完整执行顺序结合源码验证用户提交编辑内部updateCell首先调用dispatch.call(obj, onbeforechange, obj, cell, x, y, value)见 src/utils/internal.js#L557若onbeforechange返回值不为undefined该返回值会覆盖原始值见 src/utils/internal.js#L559-L562随后写入数据容器写入完成后触发onchange见 src/utils/internal.js#L700整批变更落库并刷新表格后触发一次onafterchanges其第二个参数为变更记录数组每条记录包含x、y、value、oldValue字段见 src/utils/data.js#L275-L284。因此若需要逐个单元格响应用onchange若需要整批变更结束后统一处理如一次保存用onafterchanges若需要在写入前校验或改写值用onbeforechange。四、实战示例二用 onchange 驱动图表实时刷新事件系统的价值在于把表格变成其他组件的数据源。官方高级示例展示了仅绑定一个onchange回调即可让 Highcharts 折线图随表格编辑实时更新的完整方案见 docs/jspreadsheet/v3/examples/events.md 的 Advanced Examplehtml script srchttps://bossanova.uk/jspreadsheet/v3/jexcel.js/script script srchttps://jsuites.net/v3/jsuites.js/script link relstylesheet hrefhttps://bossanova.uk/jspreadsheet/v3/jexcel.css typetext/css / link relstylesheet hrefhttps://jsuites.net/v3/jsuites.css typetext/css / script srchttps://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js/script script srchttps://code.highcharts.com/highcharts.js/script div idcontainer/div div idspreadsheet1/div script let update function (instance, cell, x, y, value) { // 若对应系列还不存在则新建一条 series if (! chart.series[y]) { let row []; for (i 1; i data1[y].length; i) { row.push(parseFloat(data1[y][i])); } chart.addSeries({ name:data1[y][0], data:row }); } else { if (x 0) { // 首列是城市名 → 更新图例名称 chart.series[y].update({ name:value }); } else { // 其余列是月度温度 → 更新对应数据点 chart.series[y].data[x-1].update({ y:parseFloat(value) }); } } } jexcel(document.getElementById(spreadsheet1), { data: [ [Tokyo, 7.0, 6.9, 9.5, 14.5, 18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6], [New York, -0.2, 0.8, 5.7, 11.3, 17.0, 22.0, 24.8, 24.1, 20.1, 14.1, 8.6, 2.5], [Berlin, -0.9, 0.6, 3.5, 8.4, 13.5, 17.0, 18.6, 17.9, 14.3, 9.0, 3.9, 1.0], [London, 3.9, 4.2, 5.7, 8.5, 11.9, 15.2, 17.0, 16.6, 14.2, 10.3, 6.6, 4.8], ], columns: [ { type: text, width:200 }, ], onchange:update, }); let chart null; chart Highcharts.chart(container, { title: { text: Monthly Average Temperature, x: -20 }, subtitle: { text: Source: WorldClimate.com, x: -20 }, xAxis: { categories: [Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec] }, yAxis: { title: { text: Temperature (°C) }, plotLines: [{ value: 0, width: 1, color: #808080 }] }, tooltip: { valueSuffix: °C }, legend: { layout: vertical, align: right, verticalAlign: middle, borderWidth: 0 }, series: [{ name: Tokyo, data: [7.0, 6.9, 9.5, 14.5, 18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6] }, { name: New York, data: [-0.2, 0.8, 5.7, 11.3, 17.0, 22.0, 24.8, 24.1, 20.1, 14.1, 8.6, 2.5] }, { name: Berlin, data: [-0.9, 0.6, 3.5, 8.4, 13.5, 17.0, 18.6, 17.9, 14.3, 9.0, 3.9, 1.0] }, { name: London, data: [3.9, 4.2, 5.7, 8.5, 11.9, 15.2, 17.0, 16.6, 14.2, 10.3, 6.6, 4.8] }] }); /script /html这个模式的核心思路是用onchange把表格的(x, y, value)三元组映射到图表 API——y对应系列城市、x对应月份索引从而让图例与数据点与表格单元格一一对应。同样的思路可以迁移到任意可视化库ECharts、D3 等或后端数据同步只要在onchange/onafterchanges中读取新值并调用目标组件的更新接口即可。五、源码级解析事件分发机制的工作原理仓库中的 src/utils/dispatch.js 是现代版本事件分发的核心实现可以反推出 Jspreadsheet 事件系统的一贯设计v3 与后续版本机制同源细节以各版本源码为准。其关键逻辑如下统一分发入口dispatch(event, ...args)是唯一的事件触发函数所有onxxx都由它调用。obj.parent用于工作表worksheet场景下把事件冒泡到父级实例。全局事件onevent每次触发任意事件时若配置了onevent函数会先被调用并接收全部参数然后才调用具体的事件回调见 src/utils/dispatch.js#L72-L78。这意味着你可以在不逐一绑定的情况下用onevent实现统一日志、埋点或权限拦截。插件事件钩子若实例注册了plugins每个插件对象的onevent也会随事件被依次调用见 src/utils/dispatch.js#L80-L91插件可通过这一机制透明地观察表格行为。返回值回传dispatch最终return ret把回调的返回值交还给调用方——这正是onbeforechange返回值能够覆盖值、onbeforeinsertrow返回false能取消操作、onbeforepaste返回解析后数据能改写粘贴内容的底层原因。onafterchanges的联动当事件名为onafterchanges时分发器还会额外触发两件事见 src/utils/dispatch.js#L94-L110调用各插件的persistence方法持久化变更若配置了persistence选项则把本次变更记录序列化为 JSON按列名/索引整理成{row, data}结构通过jSuites.ajaxPOST 到options.url并在请求成功后触发onsave事件——同时还有onbeforesave可在发送前改写或中止返回false中止。从源码结构看现代版本中onbeforechange→ 写入 →onchange→updateTable刷新 →onafterchanges是一条固定的调用链且onchange的回调签名instance, cell, x, y, value与 v3 文档保持一致见 src/utils/internal.js#L700。六、事件使用要点与注意事项before 事件是拦截点需要校验后拒绝写入/删除/插入一律在onbefore*中返回false需要静默改写值在onbeforechange中返回新值v3.4.0。切勿在 after 事件里尝试撤销已发生的 DOM 变更。onchange的cell参数可能为null从源码可见事件触发时若对应记录不存在cell会被传入null见 src/utils/internal.js#L700回调内访问cell属性前应做空值判断。updateTable与事件的关系updateTable属于渲染层回调每次数据变更后都会被调用适合做展示定制但它不能替代事件完成数据联动。展示定制用updateTable数据响应用onchange/onafterchanges二者职责互补。交互配置开关决定事件是否触发如onresizerow依赖rowResize、onmoverow/onmovecolumn依赖rowDrag/columnDrag、onsort依赖columnSorting开启绑定事件前请确认对应配置项未关闭。事件集中绑定与解绑所有事件都在初始化配置对象中声明若要动态增删现代版本可通过onevent全局钩子统一管理或在重建表格配置时更新回调引用。七、进一步探索官方 v3 事件文档docs/jspreadsheet/v3/docs/events.md事件绑定完整示例docs/jspreadsheet/v3/examples/events.mdupdateTable 表格脚本示例docs/jspreadsheet/v3/examples/table-scripting.mdv3 全部文档入口docs/jspreadsheet/v3/docs.md事件分发源码src/utils/dispatch.jsonevent全局事件、onbeforesave/onsave、persistence持久化变更链路源码src/utils/data.jssetValue→onafterchanges、src/utils/internal.jsonbeforechange/onchange触发点掌握事件系统后你可以把 Jspreadsheet 从静态表格升级为可编程数据组件用updateTable定制展示、用 before 事件做输入校验与拦截、用 after 事件驱动图表与后端同步这正是 Jspreadsheet 事件驱动的核心价值所在。赞分享前端UI组件【免费下载链接】ceJspreadsheet is a lightweight JavaScript data grid component for creating interactive data grids with advanced spreadsheet controls.项目地址https://gitcode.com/gh_mirrors/ce/ce点击查看免费下载相关推荐Jspreadsheet 4 事件系统完全指南事件绑定、updateTable 表格脚本与 onevent 全局监听Jspreadsheet 4 事件系统完全指南事件绑定、updateTable 表格脚本与 onevent 全局监听 Jspreadsheet当前仓库即 J前端UI组件Jspreadsheet v3 事件系统实战指南绑定回调、参数签名与数据驱动联动Jspreadsheet v3 事件系统实战指南绑定回调、参数签名与数据驱动联动 导读 Jspreadsheetv3 时代亦以 jexcel 为入口内置了前端UI组件Jspreadsheet v4 事件系统完全指南事件监听、返回值拦截与 updateTable 自定义表格脚本Jspreadsheet v4 事件系统完全指南事件监听、返回值拦截与 updateTable 自定义表格脚本 Jspreadsheet本仓库 gh_mir前端UI组件上一篇Conductor 任务复用指南在多租户环境中隔离 Worker 队列的工程实践下一篇ZCode 中的 AI 上下文使用可视化Context 复合组件体系实战解析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考