React Virtualized:具有相同固定高度但宽度不同的单元格的集合

时间:2017-01-12 10:03:51

标签: css reactjs infinite-scroll react-virtualized

如果我可以使用React Virtualized的Collection组件来解决我的问题,我有点困惑。我将尝试描述我正在做的事情:

我在页面上使用React Virtualized来显示两个列表/项目集合。我已经完成了第一个具有相同宽度和高度的项目的集合:

Collection where cells have same height & width

第一个系列非常直接且易于实施。 现在我正在处理包含不同大小图像的第二个集合。我希望单元格具有相同的高度但不同的宽度(当然取决于图像尺寸)。问题是行可能并不总是具有相同数量的单元格:

Collection where cells have same height but different width

使用React Virtualized可以实现这一目标吗?如果是这样,我如何确定" cellSizeAndPositionGetter"中的位置?

1 个答案:

答案 0 :(得分:1)

我最近使用react-virtualized List来显示固定高度,可变宽度图像卡的行,并且效果很好。

我的List rowRenderer使用了一系列图片卡元素。也就是说,一系列反应组件数组,如JSX。

请参阅我的最终函数cardsRows,了解如何根据元素宽度和屏幕宽度构建行。

以下是它的外观:

List rows layout

希望这有帮助!

我的代码的一些片段:

import {AutoSizer, List} from 'react-virtualized';

...

updateDimensions() {
    this.setState({
        screenWidth: window.innerWidth,
    });
}

componentDidMount() {
    window.addEventListener("resize", this.updateDimensions);
}


componentDidUpdate(prevProps, prevState) {
    const props = this.props;
    const state = this.state;

    if (JSON.stringify(props.imageDocs) !== JSON.stringify(prevProps.imageDocs) || state.screenWidth !== prevState.screenWidth)
        this.setState({
            cardsRows: cardsRows(props, state.screenWidth),
        });
}


rowRenderer({key, index, style, isScrolling}) {
    if (!this.state.cardsRows.length)
        return '';
    return (
        <div id={index} title={this.state.cardsRows[index].length} key={key} style={style}>
            {this.state.cardsRows[index]}
        </div>
    );
}

...

render() {
    return (
            <div style={styles.subMain}>
                <AutoSizer>
                    {({height, width}) => (<List height={height}
                                                 rowCount={this.state.cardsRows.length}
                                                 rowHeight={164}
                                                 rowRenderer={this.rowRenderer}
                                                 width={width}
                                                 overscanRowCount={2}
                        />
                    )}
                </AutoSizer>
            </div>
    );
}

...

const cardsRows = (props, screenWidth) => {

    const rows = [];
    let rowCards = [];
    let rowWidth = 0;
    const distanceBetweenCards = 15;

    for (const imageDoc of props.imageDocs) {
        const imageWidth = getWidth(imageDoc);

        if (rowWidth + distanceBetweenCards * 2 + imageWidth <= screenWidth) {
            rowCards.push(cardElement(imageDoc));
            rowWidth += distanceBetweenCards + imageWidth;
        }
        else {
            rows.push(rowCards);
            rowCards = [];
            rowWidth = distanceBetweenCards;
        }
    }
    if (rowCards.length) {
        rows.push(rowCards);
    }
    return rows;
};


const styles = {
    subMain: {
        position: 'absolute',
        display: 'block',
        top: 0,
        right: 0,
        left: 0,
        bottom: 0,
    }
};