reactjs 如何制作基于鼠标悬停而非单击的物料界面菜单

n3ipq98p  于 2023-02-22  发布在  React
关注(0)|答案(5)|浏览(133)

我正在使用材料界面菜单。它应该工作,因为它是,但只是使用鼠标悬停,而不是点击。这里是我的代码链接: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;
cuxqih21

cuxqih211#

下面的代码看起来工作得很合理。与你的沙盒相比,主要的变化是在按钮上使用onMouseOver={handleClick}而不是onMouseEnter。如果没有这个变化,如果鼠标不在菜单的某一部分上,它将无法可靠地打开。另一个更改是使用MenuListProps={{ onMouseLeave: handleClose }}。直接在Menu上使用onMouseLeave不会不起作用,因为菜单包括一个覆盖层,作为利用Modal的菜单的一部分,鼠标永远不会“离开”覆盖层。MenuList是菜单中显示菜单项的部分。

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;

v9tzhpje

v9tzhpje2#

我已经更新了Ryan的原始答案,以修复当您将鼠标从元素移到旁边时它不关闭的问题。
它的工作原理是在MUI背景上禁用pointerEvents,这样你就可以继续检测它后面的鼠标悬停(并在菜单容器中重新启用它)。这意味着我们也可以向按钮添加一个leave事件侦听器。
然后,它会跟踪你是否使用currentlyHovering将鼠标悬停在按钮或菜单上。
当您将鼠标悬停在按钮上时,它会显示菜单,然后当您离开时,它会启动50ms超时以关闭它,但如果我们在此期间再次悬停在按钮或菜单上,它会重置currentlyHovering并保持打开状态。
我还添加了以下代码行,以便菜单在按钮下方打开:

getContentAnchorEl={null}
anchorOrigin={{ horizontal: "left", vertical: "bottom" }}
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;

c3frrgcw

c3frrgcw3#

对菜单项使用交互式HTML工具提示效果很好,不需要单击以查看菜单项。
以下是材质UI v.4的示例。

import React from 'react';
import { withStyles, Theme, makeStyles } from '@material-ui/core/styles';
import Tooltip from '@material-ui/core/Tooltip';
import { MenuItem, IconButton } from '@material-ui/core';
import MoreVertIcon from '@material-ui/icons/MoreVert';
import styles from 'assets/jss/material-dashboard-pro-react/components/tasksStyle.js';

// @ts-ignore
const useStyles = makeStyles(styles);

const LightTooltip = withStyles((theme: Theme) => ({
  tooltip: {
    backgroundColor: theme.palette.common.white,
    color: 'rgba(0, 0, 0, 0.87)',
    boxShadow: theme.shadows[1],
    fontSize: 11,
    padding: 0,
    margin: 4,
  },
}))(Tooltip);

interface IProps {
  menus: {
    action: () => void;
    name: string;
  }[];
}
const HoverDropdown: React.FC<IProps> = ({ menus }) => {
  const classes = useStyles();
  const [showTooltip, setShowTooltip] = useState(false);
  return (
    <div>
      <LightTooltip
        interactive
        open={showTooltip}
        onOpen={() => setShowTooltip(true)}
        onClose={() => setShowTooltip(false)}
        title={
          <React.Fragment>
            {menus.map((item) => {
              return <MenuItem onClick={item.action}>{item.name}</MenuItem>;
            })}
          </React.Fragment>
        }
      >
        <IconButton
          aria-label='more'
          aria-controls='long-menu'
          aria-haspopup='true'
          className={classes.tableActionButton}
        >
          <MoreVertIcon />
        </IconButton>
      </LightTooltip>
    </div>
  );
};

export default HoverDropdown;

用法:

<HoverDropdown
        menus={[
          {
            name: 'Item 1',
            action: () => {
              history.push(
                codeGeneratorRoutes.getEditLink(row.values['node._id'])
              );
            },
          },{
            name: 'Item 2',
            action: () => {
              history.push(
                codeGeneratorRoutes.getEditLink(row.values['node._id'])
              );
            },
          },{
            name: 'Item 3',
            action: () => {
              history.push(
                codeGeneratorRoutes.getEditLink(row.values['node._id'])
              );
            },
          },{
            name: 'Item 4',
            action: () => {
              history.push(
                codeGeneratorRoutes.getEditLink(row.values['node._id'])
              );
            },
          },
        ]}
      />
ttisahbt

ttisahbt4#

我放弃了使用菜单组件,因为它实现了Popover。为了解决覆盖问题,我不得不写太多的代码。所以我尝试使用旧的CSS方式:
CSS:相对父元素+绝对菜单元素
组件:纸张+菜单列表

<ListItem>
  <Link href="#" >
    {user.name}
  </Link>
  <AccountPopover elevation={4}>
     <MenuList>
        <MenuItem>Profile</MenuItem>
        <MenuItem>Logout</MenuItem>
     </MenuList>
  </AccountPopover>
</ListItem>

样式化构件:

export const ListItem = styled(Stack)(() => ({
  position: 'relative',
  "&:hover .MuiPaper-root": {
    display: 'block'
  }
}))

export const AccountPopover = styled(Paper)(() => ({
  position: 'absolute',
  zIndex:2,
  right: 0,
  top: 30,
  width: 170,
  display: 'none'
}))
gorkyyrv

gorkyyrv5#

use **MenuListProps** in the Menu component and use your menu **closeFunction** -

MenuListProps={{ onMouseLeave: handleClose }}

example- 
 <Menu
      dense
      id="demo-positioned-menu"
      anchorEl={anchorEl}
      open={open}
      onClose={handleCloseMain}
      title={item?.title}
      anchorOrigin={{
            vertical: "bottom",
            horizontal: "right",
                    }}
      transformOrigin={{
            vertical: "top",
            horizontal: "center",
                    }}
      MenuListProps={{ onMouseLeave: handleClose }}
 />

I hope it will work perfectly.

相关问题