San*_*mar 13 reactjs material-ui
滚动或选择项目时,多选框弹出框不断跳跃
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>
);
}
Run Code Online (Sandbox Code Playgroud)
Rya*_*ell 31
跳转的原因与.net的“内容锚点”功能有关Menu。
来自https://material-ui.com/components/menus/#selected-menus(重点是我的):
如果用于项目选择,打开时,简单菜单会尝试将当前选中的菜单项与锚元素垂直对齐,初始焦点将放在选中的菜单项上。当前选择的菜单项是使用
selected属性设置的(来自 ListItem)。要使用选定的菜单项而不影响菜单的初始焦点或垂直定位,请将variant属性设置为menu。
您还可以在变体 prop的文档中找到类似的注释。
文档的另一个相关部分是Popover的getContentAnchorEl 道具的描述:
调用此函数是为了检索内容锚元素。它与
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
};
Run Code Online (Sandbox Code Playgroud)
您可能还想添加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>
);
}
Run Code Online (Sandbox Code Playgroud)
小智 5
首先,感谢 Ryan Cogswell,他很好地解释了为什么会发生这种情况以及如何解决它。我试图解决多重选择期间选择跳跃的问题,并且由于您的回答而能够实现修复。我想补充的一件事是,对于像我这样使用打字稿的其他开发人员,如果您直接实现上述解决方案,您将遇到
" Type '{ PaperProps: { style: { float: string; minWidth: number; display: string; flexWrap: string; flexDirection: string; }; };variant: string; getContentAnchorEl: null; }' 不可分配给 type '部分'。属性'variant'的类型不兼容。类型'string'不可分配给类型'"menu" | "selectedMenu" | undefined'。TS2322 "
如果您遇到这种类型兼容性问题,请像下面这样直接声明 MenuProps 将修复它。
<Select
labelId="demo-mutiple-checkbox-label"
id="demo-mutiple-checkbox"
multiple
value={personName}
onChange={handleChange}
input={<Input />}
renderValue={selected => selected.join(", ")}
MenuProps={{
PaperProps: {
style: {
maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP,
width: 250
}
},
variant: "menu",
getContentAnchorEl: null
}}>
Run Code Online (Sandbox Code Playgroud)
这对我的项目有用,但请告诉我是否有更好的解决方案来解决这种类型兼容性问题。
| 归档时间: |
|
| 查看次数: |
3604 次 |
| 最近记录: |