Ag Grid纯JS版本:Set Filter筛选后基于可见行动态更新单元格样式的实现问题
Ag Grid纯JS版本:Set Filter筛选后基于可见行动态更新单元格样式的实现问题
嘿,我完全懂你现在的困扰——你用纯JS版的AG Grid做了基于整列min/max/平均值的单元格渐变样式,但用Set Filter筛选后,样式还是基于全量原始数据的统计值,导致筛选后的颜色逻辑完全混乱,尤其是有极端值的时候,整个配色就彻底失效了对吧?
问题根源
你的calculateMinMaxMedianAverage()目前是遍历所有行数据来计算统计值的,但筛选后用户只看到部分行,这时候再用全量数据的统计值来做样式,肯定和当前可见数据不匹配。而且每次cellStyle触发时都遍历全量数据,性能上也不太友好。
解决方案思路
核心就是两点:
- 把统计值的计算范围从全量数据改成仅当前可见行
- 监听筛选变化事件,自动触发样式的重新计算和刷新
具体实现代码
1. 重写统计函数:仅基于可见行计算
用AG Grid提供的api.forEachNodeAfterFilterAndSort()方法,这个方法只会遍历经过筛选、排序后的可见节点,完美解决统计范围的问题:
function calculateMinMaxMedianAverage(api, field) { const values = []; // 只遍历筛选后的可见行节点 api.forEachNodeAfterFilterAndSort(node => { const cellValue = node.data[field]; // 排除空值,避免影响统计结果 if (cellValue !== null && cellValue !== undefined && !isNaN(cellValue)) { values.push(cellValue); } }); // 处理无数据的情况 if (values.length === 0) { return { min: 0, max: 0, median: 0, average: 0 }; } // 计算基础统计值 const min = Math.min(...values); const max = Math.max(...values); const average = values.reduce((sum, val) => sum + val, 0) / values.length; // 计算中位数 const sortedValues = [...values].sort((a, b) => a - b); const midIndex = Math.floor(sortedValues.length / 2); const median = sortedValues.length % 2 !== 0 ? sortedValues[midIndex] : (sortedValues[midIndex - 1] + sortedValues[midIndex]) / 2; return { min, max, median, average }; }
2. 监听筛选事件,自动刷新样式
在AG Grid的初始化配置里加上filterChanged事件监听,每次筛选变化时,强制刷新所有单元格样式:
const gridOptions = { // 你的其他配置(比如rowData、默认列配置等) columnDefs: [ { headerName: '目标列名', field: 'your_target_field', cellStyle: params => getCellColor(params), // 开启Set Filter filter: 'agSetColumnFilter' // 其他列配置... } ], // 监听筛选变化事件 onFilterChanged: (params) => { // 强制刷新所有单元格,触发cellStyle重新计算 params.api.refreshCells({ force: true, // 必须加这个,避免AG Grid跳过缓存的样式 columns: ['your_target_field'] // 可选:只刷新目标列,提升性能 }); } };
3. 优化你的getCellColor函数
现在它调用的统计值已经是基于可见行的了,你可以放心写你的渐变逻辑:
function getCellColor(params){ const { min, max, median, average } = calculateMinMaxMedianAverage(params.api, params.colDef.field); // 这里写你实际的渐变逻辑,举个例子: const value = params.value; // 计算当前值在可见行数据中的占比 const range = max - min; let intensity = 1; if (range !== 0) { intensity = (value - min) / range; } // 生成渐变的文字颜色(从深到浅) const grayScale = Math.floor(255 * (1 - intensity)); return { color: `rgba(${grayScale},${grayScale},${grayScale},1)`, // 也可以加背景色渐变 backgroundColor: `rgba(200,255,200,${intensity * 0.5})` }; }
额外性能优化建议
如果你的数据量很大,每次cellStyle都遍历可见行可能有点慢,可以加个缓存:
// 在闭包或全局作用域里存缓存 const columnStatsCache = {}; function calculateMinMaxMedianAverage(api, field) { // 先看缓存有没有 if (columnStatsCache[field]) { return columnStatsCache[field]; } // 没有就计算,然后存缓存 const stats = calculateMinMaxMedianAverage(api, field); columnStatsCache[field] = stats; return stats; } // 然后在filterChanged里清空缓存 onFilterChanged: (params) => { // 清空缓存,确保下次计算最新数据 Object.keys(columnStatsCache).forEach(key => delete columnStatsCache[key]); params.api.refreshCells({ force: true }); }
这样就不用每次计算样式都遍历一次可见行,性能会好很多。
备注:内容来源于stack exchange,提问作者Matte Crystal
相关产品推荐
相关产品推荐

