小编典典

滚动或选择项目时,MultiSelect框弹出框会持续跳转

reactjs

滚动或选择项目时,MultiSelect框弹出框会持续跳转

Codepen https://codesandbox.io/s/material-
demo-e5j8h

import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import Input from "@material-ui/core/Input";
import InputLabel from "@material-ui/core/InputLabel";
import MenuItem from "@material-ui/core/MenuItem";
import FormControl from "@material-ui/core/FormControl";
import ListItemText from "@material-ui/core/ListItemText";
import Select from "@material-ui/core/Select";
import Checkbox from "@material-ui/core/Checkbox";

const useStyles = makeStyles(theme => ({
  formControl: {
    margin: theme.spacing(1),
    minWidth: 120,
    maxWidth: 300
  },
  chips: {
    display: "flex",
    flexWrap: "wrap"
  },
  chip: {
    margin: 2
  },
  noLabel: {
    marginTop: theme.spacing(3)
  }
}));

const ITEM_HEIGHT = 48;
const ITEM_PADDING_TOP = 8;
const MenuProps = {
  PaperProps: {
    style: {
      maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP,
      width: 250
    }
  }
};

const names = [
  "Oliver Hansen",
  "Van Henry",
  "April Tucker",
  "Ralph Hubbard",
  "Omar Alexander",
  "Carlos Abbott",
  "Miriam Wagner",
  "Bradley Wilkerson",
  "Virginia Andrews",
  "Kelly Snyder"
];

export default function MultipleSelect() {
  const classes = useStyles();
  const [personName, setPersonName] = React.useState([]);

  const handleChange = event => {
    setPersonName(event.target.value);
  };

  return (
    <div>
      long text <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      <FormControl className={classes.formControl}>
        <InputLabel id="demo-mutiple-checkbox-label">Tag</InputLabel>
        <Select
          labelId="demo-mutiple-checkbox-label"
          id="demo-mutiple-checkbox"
          multiple
          value={personName}
          onChange={handleChange}
          input={<Input />}
          renderValue={selected => selected.join(", ")}
          MenuProps={MenuProps}
        >
          {names.map(name => (
            <MenuItem key={name} value={name}>
              <Checkbox checked={personName.indexOf(name) > -1} />
              <ListItemText primary={name} />
            </MenuItem>
          ))}
        </Select>
      </FormControl>
    </div>
  );
}

阅读 272

收藏
2020-07-22

共1个答案

小编典典

跳跃的原因与的“内容锚定”功能有关Menu

https://material-ui.com/components/menus/#selected-menus(重点是我):

如果用于项目选择,则打开后,简单菜单会 尝试将当前所选菜单项 与锚元素 垂直对齐
,并且初始焦点将放置在所选菜单项上。使用selected属性(来自ListItem)设置当前选择的菜单项。要使用选定的菜单项 而不影响 菜单
的初始焦点或垂直位置请将variant属性设置为menu

您还可以在变体prop的文档中找到类似的注释。

文档的其他相关部分是PopovergetContentAnchorEl道具的描述

调用此函数是为了检索内容锚点元素。与anchorEl道具相反。内容锚点元素应该是弹出框内的元素。它用于正确滚动和设置弹出框的位置。定位策略试图使内容锚点元素刚好位于锚点元素上方。

Select元素的默认行为是使用Select输入元素(关闭时显示选定项目的部分)作为“锚定元素”,最后选择的菜单项用作“内容锚定元素”。这意味着当Popover打开时,它将尝试将最后选择的菜单项(位于内Popover)与Select输入元素(位于后面Popover)对齐。

如果使用上的multiple属性,则Select有可能在Popover打开时更改最后选择的项目(对于单选,通常会在选择某项后立即关闭)。此外,由于并非所有菜单项都适合一次,因此有时会将最后选择的项目滚动出视线,这迫使菜单项Popover使用略微不同的逻辑进行垂直对齐。

所有这些的最终结果就是沙箱中显示的怪异跳跃。您可以通过指定以下内容来强制Popover使用contentAnchorOffset为零来解决此问题getContentAnchorEl: null

const MenuProps = {
  PaperProps: {
    style: {
      maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP,
      width: 250
    }
  },
  getContentAnchorEl: null
};

您可能还需要添加variant: "menu"以消除一些自动聚焦行为,这将导致它自动滚动到最后一个选定的项目。对于单选而言,这是很好的行为,但在多选中却不太有用,而且有些混乱。

设置variant: "menu"不足(没有getContentAnchorEl: null)来摆脱跳跃。这将导致它始终使用第一个菜单项作为内容锚,这将导致较少的跳转,但是由于更改选择时有时会滚动出第一个菜单项,因此它仍会进行一些跳转。

以下是修改后的沙箱版本的完整代码,该代码不再有任何奇怪的跳跃(唯一的变化是MenuProps):

import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import Input from "@material-ui/core/Input";
import InputLabel from "@material-ui/core/InputLabel";
import MenuItem from "@material-ui/core/MenuItem";
import FormControl from "@material-ui/core/FormControl";
import ListItemText from "@material-ui/core/ListItemText";
import Select from "@material-ui/core/Select";
import Checkbox from "@material-ui/core/Checkbox";

const useStyles = makeStyles(theme => ({
  formControl: {
    margin: theme.spacing(1),
    minWidth: 120,
    maxWidth: 300
  },
  chips: {
    display: "flex",
    flexWrap: "wrap"
  },
  chip: {
    margin: 2
  },
  noLabel: {
    marginTop: theme.spacing(3)
  }
}));

const ITEM_HEIGHT = 48;
const ITEM_PADDING_TOP = 8;
const MenuProps = {
  PaperProps: {
    style: {
      maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP,
      width: 250
    }
  },
  variant: "menu",
  getContentAnchorEl: null
};

const names = [
  "Oliver Hansen",
  "Van Henry",
  "April Tucker",
  "Ralph Hubbard",
  "Omar Alexander",
  "Carlos Abbott",
  "Miriam Wagner",
  "Bradley Wilkerson",
  "Virginia Andrews",
  "Kelly Snyder"
];

export default function MultipleSelect() {
  const classes = useStyles();
  const [personName, setPersonName] = React.useState([]);

  const handleChange = event => {
    setPersonName(event.target.value);
  };

  return (
    <div>
      long text <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      long text
      <br />
      <FormControl className={classes.formControl}>
        <InputLabel id="demo-mutiple-checkbox-label">Tag</InputLabel>
        <Select
          labelId="demo-mutiple-checkbox-label"
          id="demo-mutiple-checkbox"
          multiple
          value={personName}
          onChange={handleChange}
          input={<Input />}
          renderValue={selected => selected.join(", ")}
          MenuProps={MenuProps}
        >
          {names.map(name => (
            <MenuItem key={name} value={name}>
              <Checkbox checked={personName.indexOf(name) > -1} />
              <ListItemText primary={name} />
            </MenuItem>
          ))}
        </Select>
      </FormControl>
    </div>
  );
}

编辑修订跳转选择

2020-07-22