ClickAwayListener 组件不适用于 DragDropContext

问题描述

我使用 ButtonPopper 使用 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 周围,以便可以正确触发点击事件。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...