让键盘导航与 MUI 自动完成和 SimpleBar 一起工作以做出反应

Getting keyboard navigation to work with MUI Autocomplete and SimpleBar for react

我正在尝试将 Simplebar 滚动条添加到 MUI Material 自动完成组件,而不是默认的浏览器组件。一切正常,但这样做我失去了使用键盘导航选项列表的能力。

MUI 文档中有这个片段

ListboxComponent If you provide a custom ListboxComponent prop, you need to make sure that the intended scroll container has the role attribute set to listbox. This ensures the correct behavior of the scroll, for example when using the keyboard to navigate.

但我不知道该怎么做。

以下代码来自 MUI 文档,第一个带有自定义 ListboxComponenet 和缩短的电影列表的自动完成示例。 (https://mui.com/components/autocomplete/)

import * as React from 'react';
import TextField from '@mui/material/TextField';
import Autocomplete from '@mui/material/Autocomplete';

import SimpleBar from "simplebar-react";
import "simplebar/dist/simplebar.min.css";

export default function ComboBox() {
  return (
    <Autocomplete
      disablePortal
      id="combo-box-demo"
      options={top100Films}
      ListboxComponent={SimpleBar}
      sx={{ width: 300 }}
      renderInput={(params) => <TextField {...params} label="Movie" />}
    />
  );
}

// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top
const top100Films = [
  { label: 'City of God', year: 2002 },
  { label: 'Se7en', year: 1995 },
  { label: 'The Silence of the Lambs', year: 1991 },
  { label: "It's a Wonderful Life", year: 1946 },
  { label: 'Life Is Beautiful', year: 1997 },
  { label: 'The Usual Suspects', year: 1995 },
  { label: 'Léon: The Professional', year: 1994 },
  { label: 'Spirited Away', year: 2001 },
  { label: 'Saving Private Ryan', year: 1998 },
  { label: 'Once Upon a Time in the West', year: 1968 },
  { label: 'American History X', year: 1998 },
  { label: 'Interstellar', year: 2014 },
  { label: 'Casablanca', year: 1942 },
  { label: 'City Lights', year: 1931 },
  { label: 'Psycho', year: 1960 },
  { label: 'The Green Mile', year: 1999 },
  { label: 'The Intouchables', year: 2011 },
  { label: 'Modern Times', year: 1936 },
  { label: 'Raiders of the Lost Ark', year: 1981 },
  { label: 'Rear Window', year: 1954 },
  { label: 'The Pianist', year: 2002 },
  { label: 'The Departed', year: 2006 },
  { label: 'Terminator 2: Judgment Day', year: 1991 },
  { label: 'Back to the Future', year: 1985 },
  { label: 'Whiplash', year: 2014 },
  { label: 'Gladiator', year: 2000 },
  { label: 'Memento', year: 2000 },
];

我也尝试了以下方法,但似乎也不起作用。

ListboxComponent={(props) => <SimpleBar {...props} role="listbox" />}

如有任何帮助,我们将不胜感激。

问题其实很复杂。查看它的实现,<SimpleBar /> 不会将 React refrole 属性传递给正确的元素。我认为正确的元素是.scrollbar-content,嵌套很深,基本不可触及。

ETA: 如果你想用 document.querySelectorAll setAttribute 恶作剧变得俗气,那是行不通的。 ref 还需要指向正确的元素,我认为这在工作区端不可编码。

我能想到的最干净的解决方案是自己使用 Yarn 3() 和 patch simplebar-react,将需要的道具传递给 .scrollbar-content。然后你做:

const ListboxSimpleBar = React.forwardRef(function ListboxSimpleBar(props, ref) {
  return <SimpleBar {...props} role='listbox' listboxRef={ref} />
}

// ...
ListboxComponent={ListboxSimpleBar}

不太干净的解决方案是分叉 the repo、修补它,并将其安装为 git 依赖项。或者在您确定它可以正常工作并作为常规依赖项安装后发布到 npm。如果你不使用 Yarn 3(),那是推荐的方法。它更加繁琐并且不会收到更新,但它是一个存在的选项。

最不干净的解决方案是将 simplebar-react 代码复制到您自己的工作区中,编辑并导入它以代替真正的 simplebar-react。更黑、更乱、更有趣的选项 2,但只是勉强。