0

I'm trying to develop timeline component. This is stripped version of it to demonstrate issue:

https://jsfiddle.net/mauron85/5vverasn/

image

It should render 48 hour intervals between two dates (1/30/2007 - 1/31/2007) in table header and courier routes (rendered as cascade of squares), courier working hours and striped background in the table body.

My problem is that scrolling is only possible up to last courier route (3PM). There are no other routes, but I would like to enable scrolling to very last hour interval (11PM)

It's working when there is only one component in table body, but it's not when there more of them. In this case there is only stripe background.

image

Pseudo code:

this is working perfectly:

<ScrollSync>
    <AutoSizer disableHeight>
        <Grid className={styles.HeaderGrid} /> {/* hour intervals */}
        <div className={styles.Body}>
            <Grid /> {/* table striped background */}
        </div>
    </AutoSizer>
</ScrollSync>

but scrolling is limited when multiple children in AutoSizer:

<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>

Comment out block: {/* when following commented scrolling works as expected */} in sample project to get expected scrolling behavior.

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.

enter image description here

4

2 回答 2

1

不是 100% 确定问题在哪里,但我相信这是因为每个子组件 Grid, Collection ... 都有自己的ReactVirtualized__Collection__innerScrollContainer,宽度不同,只有最后一个 DOM 树实际上是可滚动/可见的。使用组件的 z-index 可以证实这一点。

是的。这不是特定于反应虚拟化的。如果您堆叠多个可滚动的 DOM 元素,则只有最上面的一个会接收滚动事件。您可以使用允许事件通过最顶层的元素,pointer-events: none但您仍然只有一个元素接收滚动事件。

如果你想协调多个元素的滚动,方法是将它们全部放在一个可滚动的容器中。当然,使用 react-virtualized 之类的库会更棘手,但是...查看您粘贴的图片,我建议您实际上可能不需要这两个Collections。相反,您可能能够摆脱使用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}
    />
  )
}
于 2017-02-21T05:16:00.597 回答
0

我提供了以下解决方案。基本上它是自定义 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/

于 2017-02-21T13:56:21.527 回答