如何使用 react-virtualized 制作具有响应列数的 list/grid?
How to make a list/grid with a responsive number of columns using react-virtualized?
我有一个 "card" 组件,它以设定的方式呈现对象的数据。
这些卡片组件具有预定义的宽度和高度。
这些卡片组件将显示在一个列表中,我希望该列表能够利用可用的横向 space。
我希望列数能够响应地改变。例如如果父组件对于 3 列变得太窄,那么它应该下降到使用 2 列。
从概念上讲,这很容易实现。组件尺寸是众所周知的,因此无需进行即时尺寸测量,计算适合列表宽度的组件数量也很简单,它给出了列数。
甚至可以选择使用 display:flex
并让它为您进行计算和布局。
我目前正在尝试使用 react-virtualized
来实现此响应式列列表,因为我们已经在我们的应用程序的其他情况下使用它。它对虚拟化的支持也是一个强大的吸引力。
masonry 布局似乎提供了我们想要的,但我 "can't get it to work"。
它需要一个 CellMeasurerCache
,它需要固定宽度或固定高度。这很不幸,因为我的组件具有固定的宽度和高度,因此不需要测量。
我为 CellMeasurerCache
使用了 fixedWidth
,因为 cellPositioner
需要 columnWidth
,我认为它认为不会更好需要改变。
这是我的代码:
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { RouteComponentProps } from 'react-router-dom';
import { AutoSizer, Masonry, WindowScroller, CellMeasurer, CellMeasurerCache, MasonryCellProps, createMasonryCellPositioner } from 'react-virtualized';
import { Task } from '../../store/tasks';
import { TaskCard } from './taskcard';
type TaskCardListProps = {
scrollElement?: any;
tasks: Task[];
};
type TaskCardListState = {};
export class TaskCardList extends React.Component<TaskCardListProps, TaskCardListState> {
public render() {
const { tasks, scrollElement } = this.props;
const cache = new CellMeasurerCache({
defaultHeight: 120,
defaultWidth: 400,
fixedWidth: true
});
const cellPositioner = createMasonryCellPositioner({
cellMeasurerCache: cache,
columnCount: 2,
columnWidth: 400,
spacer: 10
});
const cellRenderer = (props: MasonryCellProps) => {
const { index, key, parent, style } = props;
const task = tasks[index];
return (
<CellMeasurer cache={cache} index={index} key={key} parent={parent}>
<TaskCard { ...task } />
</CellMeasurer>
)
};
return (
<Masonry
autoHeight={false}
cellCount={tasks.length}
cellMeasurerCache={cache}
cellPositioner={cellPositioner}
cellRenderer={cellRenderer}
height={1000}
width={1500}
/>
);
}
}
我发现它确实渲染了卡片,但只有一列,并且砌体组件将 height:auto;
作为样式应用到卡片组件元素!这意味着它超过了我的固定高度,导致卡片变形。
我不确定为什么它只呈现一列,而不是两列。
.ReactVirtualized__Masonry
元素的高度为 1000px,与在 Masonry
组件上设置的一样,但它的子元素 ReactVirtualized__Masonry__innerScrollContainer
的高度为 335px;
,并且我不确定为什么,但它是 "cuts off" 可以看到的卡片。
我在 Masonry 中做错了什么吗?
Masonry 是不是错误的选择,react-virtualized
中有更好的选择吗?
我是想用锤子拧钉子吗,我应该从头开始做一些东西吗?
These card components have a pre-defined width and height.
所有卡片的宽度和高度都一样吗?如果是这样,您不需要 Masonry
组件。它适用于 pinterest.com 这样的用例。 (我实际上是专门为他们建造的。)
您描述的内容不那么复杂,因此可以以更有效的方式完成。 Here's an example 使用 List
构建您所描述的那种 UI。
如果每张卡片的尺寸不同,则 Masonry
是要使用的正确组件。
It requires a CellMeasurerCache
which needs either a fixed width, or a fixed height. That is unfortunate since my components have both a fixed width and height, and so the measurements are unnecessary.
不幸的是,这是真的。我专门为 Pinterest 的用例构建了 Masonry
组件,并尽可能地对其进行优化,使其成为 fast 而不是 generic.
我有一个 "card" 组件,它以设定的方式呈现对象的数据。
这些卡片组件具有预定义的宽度和高度。
这些卡片组件将显示在一个列表中,我希望该列表能够利用可用的横向 space。
我希望列数能够响应地改变。例如如果父组件对于 3 列变得太窄,那么它应该下降到使用 2 列。
从概念上讲,这很容易实现。组件尺寸是众所周知的,因此无需进行即时尺寸测量,计算适合列表宽度的组件数量也很简单,它给出了列数。
甚至可以选择使用 display:flex
并让它为您进行计算和布局。
我目前正在尝试使用 react-virtualized
来实现此响应式列列表,因为我们已经在我们的应用程序的其他情况下使用它。它对虚拟化的支持也是一个强大的吸引力。
masonry 布局似乎提供了我们想要的,但我 "can't get it to work"。
它需要一个 CellMeasurerCache
,它需要固定宽度或固定高度。这很不幸,因为我的组件具有固定的宽度和高度,因此不需要测量。
我为 CellMeasurerCache
使用了 fixedWidth
,因为 cellPositioner
需要 columnWidth
,我认为它认为不会更好需要改变。
这是我的代码:
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { RouteComponentProps } from 'react-router-dom';
import { AutoSizer, Masonry, WindowScroller, CellMeasurer, CellMeasurerCache, MasonryCellProps, createMasonryCellPositioner } from 'react-virtualized';
import { Task } from '../../store/tasks';
import { TaskCard } from './taskcard';
type TaskCardListProps = {
scrollElement?: any;
tasks: Task[];
};
type TaskCardListState = {};
export class TaskCardList extends React.Component<TaskCardListProps, TaskCardListState> {
public render() {
const { tasks, scrollElement } = this.props;
const cache = new CellMeasurerCache({
defaultHeight: 120,
defaultWidth: 400,
fixedWidth: true
});
const cellPositioner = createMasonryCellPositioner({
cellMeasurerCache: cache,
columnCount: 2,
columnWidth: 400,
spacer: 10
});
const cellRenderer = (props: MasonryCellProps) => {
const { index, key, parent, style } = props;
const task = tasks[index];
return (
<CellMeasurer cache={cache} index={index} key={key} parent={parent}>
<TaskCard { ...task } />
</CellMeasurer>
)
};
return (
<Masonry
autoHeight={false}
cellCount={tasks.length}
cellMeasurerCache={cache}
cellPositioner={cellPositioner}
cellRenderer={cellRenderer}
height={1000}
width={1500}
/>
);
}
}
我发现它确实渲染了卡片,但只有一列,并且砌体组件将 height:auto;
作为样式应用到卡片组件元素!这意味着它超过了我的固定高度,导致卡片变形。
我不确定为什么它只呈现一列,而不是两列。
.ReactVirtualized__Masonry
元素的高度为 1000px,与在 Masonry
组件上设置的一样,但它的子元素 ReactVirtualized__Masonry__innerScrollContainer
的高度为 335px;
,并且我不确定为什么,但它是 "cuts off" 可以看到的卡片。
我在 Masonry 中做错了什么吗?
Masonry 是不是错误的选择,react-virtualized
中有更好的选择吗?
我是想用锤子拧钉子吗,我应该从头开始做一些东西吗?
These card components have a pre-defined width and height.
所有卡片的宽度和高度都一样吗?如果是这样,您不需要 Masonry
组件。它适用于 pinterest.com 这样的用例。 (我实际上是专门为他们建造的。)
您描述的内容不那么复杂,因此可以以更有效的方式完成。 Here's an example 使用 List
构建您所描述的那种 UI。
如果每张卡片的尺寸不同,则 Masonry
是要使用的正确组件。
It requires a
CellMeasurerCache
which needs either a fixed width, or a fixed height. That is unfortunate since my components have both a fixed width and height, and so the measurements are unnecessary.
不幸的是,这是真的。我专门为 Pinterest 的用例构建了 Masonry
组件,并尽可能地对其进行优化,使其成为 fast 而不是 generic.