问题描述
我使用 Button
和 Popper
使用 Material UI 组件制作了一个下拉菜单,您可以在其中单击按钮并获得可供选择的主题列表。
要使弹出窗口消失,我们可以再次单击按钮或使用 <ClickAwayListener>
组件来侦听单击事件并关闭 Popper
。
现在我必须使列表具有拖放功能,所以我使用 react-beautiful-dnd
npm 包。
但是 <ClickAwayListener>
似乎没有当我包含 <DragDropContext>
、<Droppable>
和 <Draggable>
组件时工作。
谁能帮我弄清楚?
这是没有拖放功能的代码。 CodeSandBox 链接 https://codesandbox.io/s/gallant-newton-mfmhd?file=/demo.js
const subjectsFromBackend = [
{ name: "Physics",selected: false },{ name: "Chemistry",{ name: "Biology",{ name: "Mathematics",{ name: "Computer Science",];
const useStyles = makeStyles((theme) => ({
root: {
display: "flex"
},paper: {
marginRight: theme.spacing(2)
}
}));
export default function MenuListComposition() {
const classes = useStyles();
const [open,setopen] = React.useState(false);
const anchorRef = React.useRef(null);
const [subjects,setSubjects] = React.useState(subjectsFromBackend);
const handletoggle = () => {
setopen(!open);
};
const handleClose = () => {
setopen(false);
};
const ColumnItem = ({ subjectName,selected }) => {
return (
<>
<Grid container>
<Grid item>
<CheckBox checked={selected} />
</Grid>
<Grid item>{subjectName}</Grid>
</Grid>
</>
);
};
return (
<div className={classes.root}>
<div>
<Button
ref={anchorRef}
onClick={handletoggle}
style={{ width: 385,justifyContent: "left",textTransform: "none" }}
>
{`Subjects Selected`}
</Button>
<Popper
open={open}
anchorEl={anchorRef.current}
role={undefined}
transition
disablePortal
>
{({ TransitionProps,placement }) => (
<Grow
{...TransitionProps}
style={{
transformOrigin:
placement === "bottom" ? "center top" : "center bottom"
}}
>
<Paper style={{ maxHeight: 200,overflow: "auto",width: 385 }}>
<ClickAwayListener onClickAway={handleClose}>
<List>
{subjects.map((col,index) => (
<ListItem>
<ColumnItem
subjectName={col.name}
selected={col.selected}
/>
</ListItem>
))}
</List>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</div>
</div>
);
}
这是使用拖放的相同代码。 CodeSandBox 链接 https://codesandbox.io/s/material-demo-forked-ertti
const subjectsFromBackend = [
{ name: "Physics",selected }) => {
return (
<>
<Grid container>
<Grid item>
<CheckBox checked={selected} />
</Grid>
<Grid item>{subjectName}</Grid>
</Grid>
</>
);
};
const onDragEnd = (result,subjects,setSubjects) => {
const { source,destination } = result;
if (!destination) return;
if (source.droppableId !== destination.droppableId) return;
const copiedItems = [...subjects];
const [removed] = copiedItems.splice(source.index,1);
copiedItems.splice(destination.index,removed);
setSubjects(copiedItems);
};
return (
<div className={classes.root}>
<div>
<Button
ref={anchorRef}
onClick={handletoggle}
style={{ width: 385,placement }) => (
<Grow
{...TransitionProps}
style={{
transformOrigin:
placement === "bottom" ? "center top" : "center bottom"
}}
>
<DragDropContext
onDragEnd={(res) => onDragEnd(res,setSubjects)}
>
<Paper style={{ maxHeight: 200,width: 385 }}>
<ClickAwayListener onClickAway={handleClose}>
<Droppable droppableId={"subjectsColumn"}>
{(provided,snapshot) => (
<div
{...provided.droppableProps}
ref={provided.innerRef}
>
<List>
{subjects.map((col,index) => (
<Draggable
key={col.name}
draggableId={col.name}
index={index}
>
{(provided,snapshot) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
<ListItem>
<ColumnItem
subjectName={col.name}
selected={col.selected}
/>
</ListItem>
</div>
)}
</Draggable>
))}
</List>
{provided.placeholder}
</div>
)}
</Droppable>
</ClickAwayListener>
</Paper>
</DragDropContext>
</Grow>
)}
</Popper>
</div>
</div>
);
}
解决方法
使用拖放功能时,您需要将 ClickAwayListener
放在顶部。
return (
<ClickAwayListener
onClickAway={() => {
console.log("i got called");
handleClose();
}}
>
.....
</ClickAwayListener>
这是工作代码和框 - https://codesandbox.io/s/material-demo-forked-h1o1s?file=/demo.js:4877-4897
,我发现 ClickAwayListener
的子组件应该包裹在 div
周围,以便可以正确触发点击事件。