基于中间主体滚动事件更新AG-Grid固定列样式
问题描述
我希望在固定列与中间显示列组“重叠”时更新其样式。左侧固定列只需在onBodyScroll事件中判断e.left > 0即可,操作简单。但右侧固定列的处理更棘手,无法通过AG Grid的api/columnApi明确获取右侧偏移量。我考虑过使用refs或调用ColumnModel的私有属性,但想知道是否有更优方案,比如使用AG Grid官方函数?
当前实现(依赖私有属性)
以下是一种实现方式,但用到了ColumnModel的私有属性:
//... const [leftPinnedOverlaying, setLeftPinnedOverlaying] = useState(false); const [rightPinnedOverlaying, setRightPinnedOverlaying] = useState(true); const hasMounted = useRef(false); return ( <div style={{ width: '100%', height: '100%' }}> <pre> {JSON.stringify({leftPinnedOverlaying,rightPinnedOverlaying})} </pre> <div className="example-wrapper"> <div id="myGrid" style={{ height: '100%', width: '100%', }} className="ag-theme-alpine" > <AgGridReact defaultColDef={{ resizable: true }} debug={true} rowData={rowData} onGridReady={onGridReady} onBodyScroll={(e)=> { // first pass seems to pass non-ideal state if(!hasMounted.current) { hasMounted.current=true return } setLeftPinnedOverlaying(e.left > 0); const columnModel = e.columnApi.columnModel; // Get around these properties being private by indexing via array const scrollWidth = columnModel["scrollWidth"] || 0; const bodyWidth = columnModel["bodyWidth"] || 0; setRightPinnedOverlaying((e.left+scrollWidth) < bodyWidth) }} > <AgGridColumn headerName="Athlete" field="athlete" width={150} pinned="left" cellStyle={leftPinnedOverlaying ? {backgroundColor: 'blue'}:{backgroundColor: 'white'}} /> // ... </div> </div> </div>)
优化方案(基于官方API)
依赖私有属性存在风险——这类属性可能在AG Grid版本更新中被修改或移除。推荐使用以下官方API实现,稳定性更强:
实现思路
- 在
onBodyScroll事件中获取当前水平滚动位置scrollLeft(即e.left) - 用公开API计算左侧固定列总宽度、中间列总宽度
- 结合网格可视宽度,判断右侧固定列是否与中间列重叠
示例代码
onBodyScroll={(e) => { if(!hasMounted.current) { hasMounted.current = true; return; } const scrollLeft = e.left; const gridPanel = e.api.getGridPanelElement(); const viewportWidth = gridPanel.clientWidth; // 计算左侧固定列总宽度 const leftPinnedCols = e.columnApi.getPinnedColumns('left'); const totalLeftWidth = leftPinnedCols.reduce((sum, col) => sum + col.getActualWidth(), 0); // 计算中间非固定列总宽度 const centerCols = e.columnApi.getAllDisplayedColumns().filter(col => !col.isPinned()); const totalCenterWidth = centerCols.reduce((sum, col) => sum + col.getActualWidth(), 0); // 判断右侧固定列是否处于重叠状态 const isRightOverlaying = (scrollLeft + viewportWidth) < (totalLeftWidth + totalCenterWidth); setRightPinnedOverlaying(isRightOverlaying); // 左侧固定列判断逻辑保持不变 setLeftPinnedOverlaying(scrollLeft > 0); }}
内容的提问来源于stack exchange,提问作者Robert
相关产品推荐
相关产品推荐

