如何基于悬停而不是单击制作 Material-UI 菜单

Jor*_*Lee 3 reactjs material-ui

我正在使用 Material-UI 菜单。它应该可以正常工作,但只需使用鼠标悬停,而不是单击。这是我的代码链接:https : //codesandbox.io/embed/vn3p5j40m0

下面是我尝试过的代码。它可以正确打开,但在鼠标移开时不会关闭。

import React from "react";
import Button from "@material-ui/core/Button";
import Menu from "@material-ui/core/Menu";
import MenuItem from "@material-ui/core/MenuItem";

function SimpleMenu() {
  const [anchorEl, setAnchorEl] = React.useState(null);

  function handleClick(event) {
    setAnchorEl(event.currentTarget);
  }

  function handleClose() {
    setAnchorEl(null);
  }

  return (
    <div>
      <Button
        aria-owns={anchorEl ? "simple-menu" : undefined}
        aria-haspopup="true"
        onClick={handleClick}
        onMouseEnter={handleClick}
      >
        Open Menu
      </Button>
      <Menu
        id="simple-menu"
        anchorEl={anchorEl}
        open={Boolean(anchorEl)}
        onClose={handleClose}
        onMouseLeave={handleClose}
      >
        <MenuItem onClick={handleClose}>Profile</MenuItem>
        <MenuItem onClick={handleClose}>My account</MenuItem>
        <MenuItem onClick={handleClose}>Logout</MenuItem>
      </Menu>
    </div>
  );
}

export default SimpleMenu;
Run Code Online (Sandbox Code Playgroud)

Rya*_*ell 15

下面的代码似乎工作合理。与您的沙箱相比,主要变化是使用onMouseOver={handleClick}而不是onMouseEnter按钮。如果没有此更改,如果鼠标不在菜单部分所在的位置上,它将无法可靠地打开。另一个变化是使用MenuListProps={{ onMouseLeave: handleClose }}. onMouseLeave直接使用onMenu不起作用,因为 Menu 包含一个覆盖层作为 Menu 杠杆的一部分,Modal并且鼠标永远不会“离开”覆盖层。MenuList是 Menu 中显示菜单项的部分。

import React from "react";
import Button from "@material-ui/core/Button";
import Menu from "@material-ui/core/Menu";
import MenuItem from "@material-ui/core/MenuItem";

function SimpleMenu() {
  const [anchorEl, setAnchorEl] = React.useState(null);

  function handleClick(event) {
    if (anchorEl !== event.currentTarget) {
      setAnchorEl(event.currentTarget);
    }
  }

  function handleClose() {
    setAnchorEl(null);
  }

  return (
    <div>
      <Button
        aria-owns={anchorEl ? "simple-menu" : undefined}
        aria-haspopup="true"
        onClick={handleClick}
        onMouseOver={handleClick}
      >
        Open Menu
      </Button>
      <Menu
        id="simple-menu"
        anchorEl={anchorEl}
        open={Boolean(anchorEl)}
        onClose={handleClose}
        MenuListProps={{ onMouseLeave: handleClose }}
      >
        <MenuItem onClick={handleClose}>Profile</MenuItem>
        <MenuItem onClick={handleClose}>My account</MenuItem>
        <MenuItem onClick={handleClose}>Logout</MenuItem>
      </Menu>
    </div>
  );
}

export default SimpleMenu;
Run Code Online (Sandbox Code Playgroud)

编辑材料演示

  • 这个代码示例有一个很大的缺陷,如果我们将弹出窗口放置在按钮下方,滚动按钮以触发弹出窗口,然后向左/向右滚动,弹出窗口将不会关闭 (10认同)
  • 如果菜单列表弹出在按钮下方,而不是覆盖在按钮上,并且您甚至没有将鼠标悬停在菜单列表上并将鼠标悬停在按钮外,该怎么办? (3认同)
  • 此外,如果两个这样的按钮彼此靠近,将鼠标从一个按钮悬停到另一个按钮上将导致第一个按钮不关闭。(我知道 @RyanCogswell 说他自己并没有声称它很强大,所以只是说)。 (2认同)

bra*_*aza 10

我更新了 Ryan 的原始答案,以解决当您将鼠标从元素移到侧面时它不会关闭的问题。

它的工作原理是禁用pointerEventsMUI 背景上的 ,以便您可以继续检测其后面的悬停(并在菜单容器内再次重新启用它)。leave这意味着我们也可以向按钮添加事件侦听器。

然后,它会使用 来跟踪您是否将鼠标悬停在按钮或菜单上currentlyHovering

当您将鼠标悬停在按钮上时,它会显示菜单,然后当您离开时,它会开始超时50ms以关闭它,但如果我们再次将鼠标悬停在按钮或菜单上,它将重置currentlyHovering并保持打开状态。

我还添加了这些行,以便菜单在按钮下方打开:

getContentAnchorEl={null}
anchorOrigin={{ horizontal: "left", vertical: "bottom" }}
Run Code Online (Sandbox Code Playgroud)
import React from "react";
import Button from "@material-ui/core/Button";
import Menu from "@material-ui/core/Menu";
import MenuItem from "@material-ui/core/MenuItem";
import makeStyles from "@material-ui/styles/makeStyles";

const useStyles = makeStyles({
  popOverRoot: {
    pointerEvents: "none"
  }
});

function SimpleMenu() {
  let currentlyHovering = false;
  const styles = useStyles();

  const [anchorEl, setAnchorEl] = React.useState(null);

  function handleClick(event) {
    if (anchorEl !== event.currentTarget) {
      setAnchorEl(event.currentTarget);
    }
  }

  function handleHover() {
    currentlyHovering = true;
  }

  function handleClose() {
    setAnchorEl(null);
  }

  function handleCloseHover() {
    currentlyHovering = false;
    setTimeout(() => {
      if (!currentlyHovering) {
        handleClose();
      }
    }, 50);
  }

  return (
    <div>
      <Button
        aria-owns={anchorEl ? "simple-menu" : undefined}
        aria-haspopup="true"
        onClick={handleClick}
        onMouseOver={handleClick}
        onMouseLeave={handleCloseHover}
      >
        Open Menu
      </Button>
      <Menu
        id="simple-menu"
        anchorEl={anchorEl}
        open={Boolean(anchorEl)}
        onClose={handleClose}
        MenuListProps={{
          onMouseEnter: handleHover,
          onMouseLeave: handleCloseHover,
          style: { pointerEvents: "auto" }
        }}
        getContentAnchorEl={null}
        anchorOrigin={{ horizontal: "left", vertical: "bottom" }}
        PopoverClasses={{
          root: styles.popOverRoot
        }}
      >
        <MenuItem onClick={handleClose}>Profile</MenuItem>
        <MenuItem onClick={handleClose}>My account</MenuItem>
        <MenuItem onClick={handleClose}>Logout</MenuItem>
      </Menu>
    </div>
  );
}

export default SimpleMenu;
Run Code Online (Sandbox Code Playgroud)

编辑材质演示