无法通过具有多个网格和 Collections 的 ScrollSync 滚动到最后一个 child
Unable to scroll past the last child with ScrollSync with multiple Grids and Collections
我正在尝试开发时间轴组件。这是它的剥离版本以演示问题:
https://jsfiddle.net/mauron85/5vverasn/
它应该在 table header 中的两个日期 (1/30/2007 - 1/31/2007) 和快递路线(呈现为级联的正方形)之间呈现 48 小时间隔,快递table body.
中的工作时间和条纹背景
我的问题是只能滚动到最后一条快递路线(下午 3 点)。没有其他路线,但我想启用滚动到最后一小时间隔(晚上 11 点)
当 table body 中只有一个组件时,它可以工作,但当有更多组件时,它就不会工作。在这种情况下,只有条纹背景。
伪代码:
这很完美:
<ScrollSync>
<AutoSizer disableHeight>
<Grid className={styles.HeaderGrid} /> {/* hour intervals */}
<div className={styles.Body}>
<Grid /> {/* table striped background */}
</div>
</AutoSizer>
</ScrollSync>
但在 AutoSizer 中多个 children 时滚动受到限制:
<ScrollSync>
<AutoSizer disableHeight>
<div>
<Grid className={styles.HeaderGrid} /> {/* hour intervals */}
<div className={styles.Body}>
<Grid /> {/* table striped background */}
<Collection/> {/* courier routes has to be collection */}
<Collection/> {/* courier working hours has to be collection */}
</div>
</div>
</AutoSizer>
</ScrollSync>
注释块:{/* 当以下注释滚动按预期工作时 */} 在 sample project 中获得预期的滚动行为。
不是 100% 确定问题在哪里,但我相信这是因为每个 child 组件网格,Collection ... 都有自己的 ReactVirtualized__Collection__innerScrollContainer,它有不同的宽度,在 DOM 树中只有最后一个实际上是 scrollable/visible。使用 z-index 个组件证实了这一点。
Not 100% sure where is the catch, but I believe it's because every child component Grid, Collection ... has its own ReactVirtualized__Collection__innerScrollContainer
, which has different width and only very last in DOM tree is actually scrollable/visible. Playing with z-index of components confirms this.
是的。这不是 react-virtualized 特有的任何内容。如果您堆叠多个可滚动的 DOM 元素,则只有 top-most 元素会接收滚动事件。您可以使用 pointer-events: none
允许事件通过 top-most 元素,但您仍然只有一个元素接收滚动事件。
如果你想协调多个元素的滚动,方法是将它们全部放在一个可滚动的容器中。当然,使用像 react-virtualized 这样的库会比较棘手,但是...看看您粘贴的图片,我建议您实际上可能不需要这两个 Collection
。相反,您可以使用 Grid
并提供您自己的自定义 cellRangeRenderer
来渲染叠加层 UI。 (这是 属性 暴露处理的那种事情。)这也会表现得更好,因为 Grid
比 Collection
表现更好(1 个组件通常比 3 个组件表现更好)。
以下是我的建议的粗略概述:
import { defaultCellRangeRenderer, Grid } from 'react-virtualized'
function cellRangeRenderer (props) {
// Use the default cellRangeRenderer to render your Grid's cells
// No need to re-implement that
const children = defaultCellRangeRenderer(props)
// cellRangeRenderer is passed params representing the Grid's current offset
// Use these to decide what Collection items you should display
const { scrollLeft, scrollTop } = props
// Add the additional items you were putting into the Collection
// They were just absolutely positioned elements anyway so treat them the same
children.push(
<div style={...}>This could be a Collection cell</div>
)
// NOTE If you think your Grid will be larger than 1.5M pixels,
// You will also need to account for compression, see:
// https://github.com/bvaughn/react-virtualized/blob/eb50a1569c8a59ec3d296145b636dff4b24ccae8/source/Grid/defaultCellRangeRenderer.js#L77-L83
return children
}
function YourGrid (props) {
return (
<Grid
cellRangeRenderer={cellRangeRenderer}
{...props}
/>
)
}
我提出了以下解决方案。基本上它是自定义 Scroller 组件,它包装所有可滚动组件并设置所有可滚动组件的宽度和高度,高度和宽度最大。
<Scroller
width={width}
height={height}
leftOffset={100}
totalWidth={totalWidth}
totalHeight={totalHeight}
scrollTop={scrollTop}
scrollLeft={scrollLeft}
onScroll={onScroll}
>
<div className="Body">
<div className="BodyPart">
<Grid
className="BodyGrid"
width={totalWidth}
height={totalHeight}
columnWidth={columnWidth}
columnCount={columnCount}
rowHeight={rowHeight}
rowCount={rowCount}
overscanColumnCount={overscanColumnCount}
overscanRowCount={overscanRowCount}
cellRenderer={this.renderBodyCell}
scrollTop={scrollTop}
scrollLeft={scrollLeft}
/>
</div>
<div className="BodyPart">
<Routes
startTime={startDate.getTime()}
routes={Object.values(routes)}
courierIds={courierIds}
height={totalHeight}
width={totalWidth}
rowHeight={rowHeight}
columnWidth={columnWidth}
scrollTop={scrollTop}
scrollLeft={scrollLeft}
/>
</div>
</div>
</Scroller>
我正在尝试开发时间轴组件。这是它的剥离版本以演示问题:
https://jsfiddle.net/mauron85/5vverasn/
它应该在 table header 中的两个日期 (1/30/2007 - 1/31/2007) 和快递路线(呈现为级联的正方形)之间呈现 48 小时间隔,快递table body.
中的工作时间和条纹背景我的问题是只能滚动到最后一条快递路线(下午 3 点)。没有其他路线,但我想启用滚动到最后一小时间隔(晚上 11 点)
当 table body 中只有一个组件时,它可以工作,但当有更多组件时,它就不会工作。在这种情况下,只有条纹背景。
伪代码:
这很完美:
<ScrollSync>
<AutoSizer disableHeight>
<Grid className={styles.HeaderGrid} /> {/* hour intervals */}
<div className={styles.Body}>
<Grid /> {/* table striped background */}
</div>
</AutoSizer>
</ScrollSync>
但在 AutoSizer 中多个 children 时滚动受到限制:
<ScrollSync>
<AutoSizer disableHeight>
<div>
<Grid className={styles.HeaderGrid} /> {/* hour intervals */}
<div className={styles.Body}>
<Grid /> {/* table striped background */}
<Collection/> {/* courier routes has to be collection */}
<Collection/> {/* courier working hours has to be collection */}
</div>
</div>
</AutoSizer>
</ScrollSync>
注释块:{/* 当以下注释滚动按预期工作时 */} 在 sample project 中获得预期的滚动行为。
不是 100% 确定问题在哪里,但我相信这是因为每个 child 组件网格,Collection ... 都有自己的 ReactVirtualized__Collection__innerScrollContainer,它有不同的宽度,在 DOM 树中只有最后一个实际上是 scrollable/visible。使用 z-index 个组件证实了这一点。
Not 100% sure where is the catch, but I believe it's because every child component Grid, Collection ... has its own
ReactVirtualized__Collection__innerScrollContainer
, which has different width and only very last in DOM tree is actually scrollable/visible. Playing with z-index of components confirms this.
是的。这不是 react-virtualized 特有的任何内容。如果您堆叠多个可滚动的 DOM 元素,则只有 top-most 元素会接收滚动事件。您可以使用 pointer-events: none
允许事件通过 top-most 元素,但您仍然只有一个元素接收滚动事件。
如果你想协调多个元素的滚动,方法是将它们全部放在一个可滚动的容器中。当然,使用像 react-virtualized 这样的库会比较棘手,但是...看看您粘贴的图片,我建议您实际上可能不需要这两个 Collection
。相反,您可以使用 Grid
并提供您自己的自定义 cellRangeRenderer
来渲染叠加层 UI。 (这是 属性 暴露处理的那种事情。)这也会表现得更好,因为 Grid
比 Collection
表现更好(1 个组件通常比 3 个组件表现更好)。
以下是我的建议的粗略概述:
import { defaultCellRangeRenderer, Grid } from 'react-virtualized'
function cellRangeRenderer (props) {
// Use the default cellRangeRenderer to render your Grid's cells
// No need to re-implement that
const children = defaultCellRangeRenderer(props)
// cellRangeRenderer is passed params representing the Grid's current offset
// Use these to decide what Collection items you should display
const { scrollLeft, scrollTop } = props
// Add the additional items you were putting into the Collection
// They were just absolutely positioned elements anyway so treat them the same
children.push(
<div style={...}>This could be a Collection cell</div>
)
// NOTE If you think your Grid will be larger than 1.5M pixels,
// You will also need to account for compression, see:
// https://github.com/bvaughn/react-virtualized/blob/eb50a1569c8a59ec3d296145b636dff4b24ccae8/source/Grid/defaultCellRangeRenderer.js#L77-L83
return children
}
function YourGrid (props) {
return (
<Grid
cellRangeRenderer={cellRangeRenderer}
{...props}
/>
)
}
我提出了以下解决方案。基本上它是自定义 Scroller 组件,它包装所有可滚动组件并设置所有可滚动组件的宽度和高度,高度和宽度最大。
<Scroller
width={width}
height={height}
leftOffset={100}
totalWidth={totalWidth}
totalHeight={totalHeight}
scrollTop={scrollTop}
scrollLeft={scrollLeft}
onScroll={onScroll}
>
<div className="Body">
<div className="BodyPart">
<Grid
className="BodyGrid"
width={totalWidth}
height={totalHeight}
columnWidth={columnWidth}
columnCount={columnCount}
rowHeight={rowHeight}
rowCount={rowCount}
overscanColumnCount={overscanColumnCount}
overscanRowCount={overscanRowCount}
cellRenderer={this.renderBodyCell}
scrollTop={scrollTop}
scrollLeft={scrollLeft}
/>
</div>
<div className="BodyPart">
<Routes
startTime={startDate.getTime()}
routes={Object.values(routes)}
courierIds={courierIds}
height={totalHeight}
width={totalWidth}
rowHeight={rowHeight}
columnWidth={columnWidth}
scrollTop={scrollTop}
scrollLeft={scrollLeft}
/>
</div>
</div>
</Scroller>