如何将 Material-UI Autocomplete 与 virtua 一起使用?

问题描述 投票:0回答:1

有一些使用 Material-UI Autocomplete 与列表虚拟化库的示例。 MUI 在其一个示例中采用了react-window库,但值得注意的是,这种方法需要了解项目高度,这可能有点麻烦。

我们正在考虑改建一个更现代化的图书馆。是否有一个可用的功能示例来演示 Virtua 库 与 MUI 的自动完成虚拟化的集成?

material-ui
1个回答
0
投票

使用

virtua
的实现要简单得多。您需要避免使用其
VList
组件,而只需手动使用
Virtualizer
VList
只是
Virtualizer
的包装,具有您不需要的 DOM 结构和样式(感谢 MUI)。这是我写的:

虚拟化列表框.tsx

请注意,

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;

虚拟化自动完成.tsx

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>
      )}
    />
  );
};

替代 VirtualizedListbox.tsx

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;
© www.soinside.com 2019 - 2024. All rights reserved.