如何在AG Grid中创建不受自定义排序影响的Running Totals计算列
AG Grid 实现无排序依赖的滚动累计自定义列方案
核心实现思路
不要将滚动累计的计算逻辑和AG Grid当前渲染的行顺序绑定,否则只要用户调整排序,计算时取到的「前序行」就会变成渲染顺序的上一行,而非业务规则定义的日期更早的行,直接导致计算错误。
正确的逻辑是 完全基于业务规则的基准顺序(日期从早到晚)预计算每行的固定累计值,直接存入原始行数据,后续不管用户怎么调整排序、拖拽列,累计值都是提前算好的固定正确值,不会随渲染顺序变化。
具体实现步骤
1. 脱离Grid渲染状态,预计算累计值
拿到全量原始行数据后,单独拷贝一份数据副本,按照业务定义的日期先后规则排序,逐行计算滚动累计结果,直接写回原始行数据的自定义字段中。这一步的排序仅用于计算,不会修改Grid当前的渲染排序状态。
参考实现代码:
// 全量原始行数据,和Grid当前排序/筛选状态无关 const sourceRowData = [/* 包含Price、Date字段的原始数据数组 */] // 拷贝数据后按业务规则(日期升序,即最早的日期排最前)排序,用于计算 const calcDataSet = [...sourceRowData].sort((prev, curr) => new Date(prev.Date) - new Date(curr.Date)) // 逐行计算累计值,写回原始行数据 // 注意:初始累计值根据业务实际基数调整,匹配示例效果初始值设为5即可 let runningTotal = 5 calcDataSet.forEach(row => { runningTotal += row.Price // 累计值直接存在原始行对象上,后续Grid渲染直接取该字段 row.runningPrice = runningTotal })
计算后匹配示例的结果如下:
| Price | Date | Running Price |
|---|---|---|
| 5 | 2天前 | 10 |
| 7 | 昨天 | 17 |
| 9 | 今天 | 26 |
2. 注册AG Grid自定义列
在列定义中直接新增累计列,字段指向预计算存入的runningPrice即可,不需要编写依赖前后渲染行的动态取值逻辑。
参考列定义代码:
const columnDefs = [ { field: 'Price', headerName: '价格' }, { field: 'Date', headerName: '日期' }, { field: 'runningPrice', headerName: '累计价格(Running Price)' } ]
特殊场景适配
- 支持Price在线编辑:监听AG Grid的单元格编辑提交事件,只要某行的Price值被修改,重新执行一遍上述预计算逻辑,更新所有行的
runningPrice字段,Grid会自动触发重渲染。 - 筛选后重算累计:如果业务要求筛选后累计值仅统计筛选结果范围内的数据,监听Grid的
filterChanged事件,拿到筛选后的全量数据行,仍按日期升序规则重新计算累计值更新即可,依然不依赖当前渲染排序。
方案优势
- 完全不需要强制固定Date列的排序,用户可自由按任意列排序、配置自定义排序规则,累计值始终符合业务计算逻辑,不会失效。
- 计算仅在数据初始化、编辑、筛选变化时执行一次,不需要在单元格渲染时动态遍历行找关联数据,大数据量下性能表现远好于动态计算方案。
- 预计算生成的
runningPrice是普通数据字段,可直接被已配置的AdapTable计算列引用,不需要改动现有AdapTable配置。
内容的提问来源于stack exchange,提问作者Simone
相关产品推荐
相关产品推荐

