我可能正在尝试做一些不受支持的事情,但我正在尝试将 react-virtualized 的 CellMeasurer 与 MultiGrid 一起使用。我还使用 aScrollSync
来检测用户何时一直向右滚动并显示/隐藏指示器。
需要注意的是,我有一个选项卡控件来操作哪些数据(行和列)。当数据发生变化时,我在我的 redux 存储中设置了一个标志,并使用它来重新测量我的单元格。
它的工作方式与我的预期非常接近。我第一次进入新标签时,除了两个例外,所有单元格都被正确测量。
1)第一列(1个固定列)重新测量,但左上角和左下角网格的宽度不更新。这会在新尺寸和默认尺寸之间留下一个差距。一旦我滚动,它就会自行修复 - 很确定,因为我有 ScrollSync。
2) 列索引 1 永远不会小于默认宽度。这是第一个非固定列。
适用于更大的内容:
然后,主要问题是当我返回之前已经显示的选项卡时。发生这种情况时,即使我的新数据标志仍在触发重新测量,上一个选项卡中存在的列中的测量值也会继续存在。我认为我需要清除缓存,但到目前为止我的尝试已导致所有列都变为默认宽度。是否有一定的 , 序列,CellMeasurerCache.clearAll
这对我来说可以正常工作吗?MultiGrid.measureAllCells
MultiGrid.recomputeGridSize
使成为
render() {
const { tableName, ui } = this.props;
const dataSet = this.getFinalData();
console.log('rendering');
return (
<ScrollSync>
{({
// clientHeight,
// scrollHeight,
// scrollTop,
clientWidth, // width of the grid
scrollWidth, // width of the entire page
scrollLeft, // how far the user has scrolled
onScroll,
}) => {
// if we have new daya, default yo scrolled left
const newData = Ui.getTableNewData(ui, tableName);
const scrolledAllRight = !newData &&
(scrollLeft + clientWidth >= scrollWidth);
const scrolledAllLeft = newData || scrollLeft === 0;
return (
<AutoSizer>
{({ width, height }) => {
const boxShadow = scrolledAllLeft ? false :
'1px -3px 3px #a2a2a2';
return (
<div className="grid-container">
<MultiGrid
cellRenderer={this.cellRenderer}
columnWidth={this.getColumnWidth}
columnCount={this.getColumnCount()}
fixedColumnCount={1}
height={height}
rowHeight={this.getRowHeight}
rowCount={dataSet.length}
fixedRowCount={1}
deferredMeasurementCache={this.cellSizeCache}
noRowsRenderer={DataGrid.emptyRenderer}
width={width}
className={classNames('data-grid', {
'scrolled-left': scrolledAllLeft,
})}
onScroll={onScroll}
styleBottomLeftGrid={{ boxShadow }}
ref={(grid) => {
this.mainGrid = grid;
}}
/>
<div
className={classNames('scroll-x-indicator', {
faded: scrolledAllRight,
})}
>
<i className="fa fa-fw fa-angle-double-right" />
</div>
</div>
);
}}
</AutoSizer>
);
}}
</ScrollSync>
);
}
单元格渲染器
cellRenderer({ columnIndex, rowIndex, style, parent }) {
const data = this.getFinalData(rowIndex);
const column = this.getColumn(columnIndex);
return (
<CellMeasurer
cache={this.cellSizeCache}
columnIndex={columnIndex}
key={`${columnIndex},${rowIndex}`}
parent={parent}
rowIndex={rowIndex}
ref={(cellMeasurer) => {
this.cellMeasurer = cellMeasurer;
}}
>
<div
style={{
...style,
maxWidth: 500,
}}
className={classNames({
'grid-header-cell': rowIndex === 0,
'grid-cell': rowIndex > 0,
'grid-row-even': rowIndex % 2 === 0,
'first-col': columnIndex === 0,
'last-col': columnIndex === this.getColumnCount(),
})}
>
<div className="grid-cell-data">
{data[column.key]}
</div>
</div>
</CellMeasurer>
);
}
组件生命周期
constructor() {
super();
this.cellSizeCache = new CellMeasurerCache({
defaultWidth: 300,
});
// used to update the sizing on command
this.cellMeasurer = null;
this.mainGrid = null;
// this binding for event methods
this.sort = this.sort.bind(this);
this.cellRenderer = this.cellRenderer.bind(this);
this.getColumnWidth = this.getColumnWidth.bind(this);
this.getRowHeight = this.getRowHeight.bind(this);
}
componentDidMount() {
this.componentDidUpdate();
setTimeout(() => {
this.mainGrid.recomputeGridSize();
setTimeout(() => {
this.mainGrid.measureAllCells();
}, 1);
}, 1);
}
componentDidUpdate() {
const { tableName, ui } = this.props;
// if we did have new data, it is now complete
if (Ui.getTableNewData(ui, tableName)) {
console.log('clearing');
setTimeout(() => {
this.mainGrid.measureAllCells();
setTimeout(() => {
this.mainGrid.recomputeGridSize();
}, 1);
}, 1);
this.props.setTableNewData(tableName, false);
}
}
编辑 这是一个 plunker。这个例子展示了我所解释的大部分内容。它也给行提供了比预期更高的高度(无法分辨与我的其他实现有什么不同)