无法通过具有多个网格和 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。 (这是 属性 暴露处理的那种事情。)这也会表现得更好,因为 GridCollection 表现更好(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/97dj3baq/