有一些使用 Material-UI Autocomplete 与列表虚拟化库的示例。 MUI 在其一个示例中采用了react-window库,但值得注意的是,这种方法需要了解项目高度,这可能有点麻烦。
我们正在考虑改建一个更现代化的图书馆。是否有一个可用的功能示例来演示 Virtua 库 与 MUI 的自动完成虚拟化的集成?
使用
virtua
的实现要简单得多。您需要避免使用其 VList
组件,而只需手动使用 Virtualizer
。 VList
只是 Virtualizer
的包装,具有您不需要的 DOM 结构和样式(感谢 MUI)。这是我写的:
请注意,
Container
和 Item
组件是可选的,我刚刚将它们包含在内以获得正确的语义 HTML,其中 DOM 结构为 ul > li > ...
。但如果你不关心 DOM 结构,你可以省略组件,只渲染 <Virtualizer>
,无需任何 props 或自定义。
import React, { forwardRef } from 'react';
import { Virtualizer, CustomItemComponentProps, CustomContainerComponentProps } from 'virtua';
import { Box, List } from '@mui/material';
const Container = forwardRef<
HTMLUListElement,
CustomContainerComponentProps
>(({ children, style }, ref) => {
return (
<List dense ref={ref} style={style}>
{children}
</List>
);
});
const Item = forwardRef<
HTMLDivElement,
CustomItemComponentProps
>(({ children, style }, ref) => {
children = children as React.ReactElement;
return React.cloneElement(children, {
ref,
style: { ...children.props.style, ...style },
});
});
const VirtualizedListbox = forwardRef<
HTMLElement,
React.HTMLAttributes<HTMLElement
>>(({ children, ...listboxProps }, ref) => {
return (
<Box
ref={ref}
{...listboxProps}
// This is how you would set the max height to something different
// sx={{
// // Include role in selector for higher specificity
// '&[role="listbox"]': {
// maxHeight: 100,
// },
// }}
>
<Virtualizer
as={Container}
item={Item}
>
{children}
</Virtualizer>
</Box>
);
});
export default VirtualizedListbox;
import VirtualizedListbox from './VirtualizedListbox';
const VirtualizedAutocomplete = ({ yourProps }) => {
return (
<Autocomplete
ListboxComponent={VirtualizedListbox} // <-- This is the key difference
// TODO: Add all of your other props
// renderOption can do whatever you want.
// This is just an example showing that it works right out of the box.
renderOption={(props, option, state) => (
<ListItem {...props}>
<Checkbox
icon={<CheckboxOutlineBlankIcon fontSize="small" />}
checkedIcon={<CheckboxIcon fontSize="small" />}
checked={state.selected}
/>
{option.label}
</ListItem>
)}
/>
);
};
import React, { forwardRef } from 'react';
import { Virtualizer } from 'virtua';
import { Box } from '@mui/material';
const VirtualizedListbox = forwardRef<
HTMLElement,
React.HTMLAttributes<HTMLElement
>>(({ children, ...listboxProps }, ref) => {
return (
<Box ref={ref} {...listboxProps}>
<Virtualizer>
{children}
</Virtualizer>
</Box>
);
});
export default VirtualizedListbox;