React Virtualized 支持 flex-wrap/inline-block 样式的项目包装吗?

jdu*_*ing 2 reactjs react-virtualized

我目前有一个项目列表,例如<ul><li/><li/>...</ul>,每个项目的样式都是display: inline-block。这些项目不是固定的高度或宽度,尽管我可能可以将它们固定,并且每个项目都包含缩略图,有时还包含文本。

随着窗口宽度的变化,列表会相应地换行,没有水平滚动条。例如,列表可能以 3 个项目开始,它们全部水平排列在窗口内的一行上:

| 1 2 3     |
Run Code Online (Sandbox Code Playgroud)

然后添加更多项目,并且这些项目开始换行到第二行:

| 1 2 3 4 5 |
| 6 7 8     |
Run Code Online (Sandbox Code Playgroud)

然后,如果窗口宽度发生变化,项目将重新换行:

| 1 2 3 4 5 6 7 |
| 8             |
Run Code Online (Sandbox Code Playgroud)

当有数千个项目时,性能肯定会受到影响,所以我想看看是否有一种方法可以虚拟化列表。从我阅读的文档来看,React Virtualized 库目前似乎不支持此功能,但我想检查一下。该Collection组件看起来可能很接近,但我认为它不会随着窗口大小的调整而动态改变宽度或高度。

如果这种项目包装是可能的,是否有任何示例实现?

bva*_*ghn 5

从我阅读文档来看,React Virtualized 库目前似乎不支持此功能

我很想知道文档的哪一部分给了您这样的印象。您的用例听起来像是一个反应虚拟化设备足以处理。:)

Collection组件看起来可能很接近

Collection是用于其他目的的。也许我最近一次会议演讲中的这些幻灯片可以澄清这一点。基本上,Collection用于非线性数据(例如甘特图、Pinterest 布局等)。它更灵活,但会牺牲性能。您的用例听起来非常适合List. :)

更新答案

您可以使用ListAutoSizer来完成此操作。您只需要使用可用宽度和项目高度来计算行数。不太复杂。:)

这是一个 Plunker 示例,来源如下:

const { AutoSizer, List } = ReactVirtualized

const ITEMS_COUNT = 100
const ITEM_SIZE = 100

// Render your list
ReactDOM.render(
  <AutoSizer>
    {({ height, width }) => {
      const itemsPerRow = Math.floor(width / ITEM_SIZE);
      const rowCount = Math.ceil(ITEMS_COUNT / itemsPerRow);

      return (
        <List
          className='List'
          width={width}
          height={height}
          rowCount={rowCount}
          rowHeight={ITEM_SIZE}
          rowRenderer={
            ({ index, key, style }) => {
              const items = [];
              const convertedIndex = index * itemsPerRow;

              for (let i = convertedIndex; i < convertedIndex + itemsPerRow; i++) {
                items.push(
                  <div
                    className='Item'
                    key={i}
                  >
                    Item {i}
                  </div>
                )
              }

              return (
                <div
                  className='Row'
                  key={key}
                  style={style}
                >
                  {items}
                </div>
              )
            }
          }
        />
      )
    }}
  </AutoSizer>,
  document.getElementById('example')
)
Run Code Online (Sandbox Code Playgroud)

初步答复

这就是我或多或少会做的事情:

export default class Example extends Component {
  static propTypes = {
    list: PropTypes.instanceOf(Immutable.List).isRequired
  }

  constructor (props, context) {
    super(props, context)

    this._rowRenderer = this._rowRenderer.bind(this)
    this._rowRendererAdapter = this._rowRendererAdapter.bind(this)
  }

  shouldComponentUpdate (nextProps, nextState) {
    return shallowCompare(this, nextProps, nextState)
  }

  render () {
    const { list } = this.props

    return (
      <AutoSizer>
        {({ height, width }) => (
          <CellMeasurer
            cellRenderer={this._rowRendererAdapter}
            columnCount={1}
            rowCount={list.size}
            width={width}
          >
            {({ getRowHeight }) => (
              <List
                height={height}
                rowCount={list.size}
                rowHeight={getRowHeight}
                rowRenderer={this._rowRenderer}
                width={width}
              />
            )}
          </CellMeasurer>
        )}
      </AutoSizer>
    )
  }

  _getDatum (index) {
    const { list } = this.props

    return list.get(index % list.size)
  }

  _rowRenderer ({ index, key, style }) {
    const datum = this._getDatum(index)

    return (
      <div
        key={key}
        style={style}
      >
        {datum.name /* Or whatever */}
      </div>
    )
  }

  _rowRendererAdapter ({ rowIndex, ...rest }) {
    return this._rowRenderer({
      index: rowIndex,
      ...rest
    })
  }
}
Run Code Online (Sandbox Code Playgroud)