reactjs 如何保持显示'popover'悬停在锚El和'popover'以及?

kpbwa7wx  于 2022-12-29  发布在  React
关注(0)|答案(7)|浏览(401)

在这个material-ui的例子中https://material-ui.com/utils/popover/#mouse-over-interaction
对于示例material-ui www.example.com,请执行以下步骤https://material-ui.com/utils/popover/#mouse-over-interaction
1.在上面的示例中,将鼠标停留在文本Hover with a Popover.上---您将看到popover
1.尝试将鼠标移到popover附近---popover消失了,对吗?但是我想显示弹出窗口,即使我悬停在popover
并且仅当用户没有悬停在popoverHover with a Popover.(基本上是anchorEl)上时,才使弹出消失
我正在从他们的演示中复制代码

import React from 'react';
    import PropTypes from 'prop-types';
    import Popover from '@material-ui/core/Popover';
    import Typography from '@material-ui/core/Typography';
    import { withStyles } from '@material-ui/core/styles';

    const styles = theme => ({
      popover: {
        pointerEvents: 'none',
      },
      paper: {
        padding: theme.spacing.unit,
      },
    });

    class MouseOverPopover extends React.Component {
      state = {
        anchorEl: null,
      };

      handlePopoverOpen = event => {
        this.setState({ anchorEl: event.currentTarget });
      };

      handlePopoverClose = () => {
        this.setState({ anchorEl: null });
      };

      render() {
        const { classes } = this.props;
        const { anchorEl } = this.state;
        const open = Boolean(anchorEl);

        return (
          <div>
            <Typography
              aria-owns={open ? 'mouse-over-popover' : undefined}
              aria-haspopup="true"
              onMouseEnter={this.handlePopoverOpen}
              onMouseLeave={this.handlePopoverClose}
            >
              Hover with a Popover.
            </Typography>
            <Popover
              id="mouse-over-popover"
              className={classes.popover}
              classes={{
                paper: classes.paper,
              }}
              open={open}
              anchorEl={anchorEl}
              anchorOrigin={{
                vertical: 'bottom',
                horizontal: 'left',
              }}
              transformOrigin={{
                vertical: 'top',
                horizontal: 'left',
              }}
              onClose={this.handlePopoverClose}
              disableRestoreFocus
            >
              <Typography>I use Popover.</Typography>
            </Popover>
          </div>
        );
      }
    }

    MouseOverPopover.propTypes = {
      classes: PropTypes.object.isRequired,
    };

    export default withStyles(styles)(MouseOverPopover);

这里需要做什么代码更改?您可以尝试https://codesandbox.io/s/6l3wk6kv3

xqkwcwgp

xqkwcwgp1#

我也遇到了同样的问题,没有找到任何答案,我花了一段时间才明白如何解决它。
实际上问题来自指针事件:弹出窗口上不需要任何设置来防止同时触发onMouseEnter/onMouseLeave。
但是您可以为弹出窗口指针事件的内容设置:自动。
然后,您可以在弹出窗口的内容上添加onMouseEnter和onMouseLeave。
下面是一个例子,使它更明确:

import React, { useState, useRef } from 'react';
import { makeStyles } from '@material-ui/core/styles';
import { Popover } from '@material-ui/core';

const useStyles = makeStyles(theme => ({
  popover: {
    pointerEvents: 'none',
  },
  popoverContent: {
    pointerEvents: 'auto',
  },
}));

const MyComponent = ({ loading, login, wrong, clearWrongLogin }: Props) => {
  const [openedPopover, setOpenedPopover] = useState(false)
  const popoverAnchor = useRef(null);

  const popoverEnter = ({ currentTarget }) => {
    setOpenedPopover(true)
  };

  const popoverLeave = ({ currentTarget }) => {
    setOpenedPopover(false)
  };

  const classes = useStyles();

return (
    <div>
         <span
          ref={popoverAnchor}
          aria-owns="mouse-over-popover"
          aria-haspopup="true"
          onMouseEnter={popoverEnter}
          onMouseLeave={popoverLeave}
        >Hover this el !
        </span>
        <Popover
        id="mouse-over-popover"
        className={classes.popover}
        classes={{
          paper: classes.popoverContent,
        }}
        open={openedPopover}
        anchorEl={popoverAnchor.current}
        anchorOrigin={{
          vertical: 'bottom',
          horizontal: 'right',
        }}
        transformOrigin={{
          vertical: 'top',
          horizontal: 'left',
        }}
        PaperProps={{onMouseEnter: popoverEnter, onMouseLeave: popoverLeave}}
      >
        <div>
          My popover content...
        </div>
      </Popover>
    </div>
  );
};

export default MyComponent
zf2sa74q

zf2sa74q2#

import React from "react";
import Popover from "@material-ui/core/Popover";
import Typography from "@material-ui/core/Typography";
import { makeStyles } from "@material-ui/core/styles";

const useStyles = makeStyles(theme => ({
  popover: {
    pointerEvents: "none"
  },
  paper: {
    pointerEvents: "auto",
    padding: theme.spacing(1)
  }
}));

export default function MouseOverPopover() {
  const classes = useStyles();
  const [anchorEl, setAnchorEl] = React.useState(null);

  const handlePopoverOpen = event => {
    setAnchorEl(event.currentTarget);
  };

  const handlePopoverClose = () => {
    setAnchorEl(null);
  };

  const open = Boolean(anchorEl);

  return (
    <div onMouseEnter={handlePopoverOpen} onMouseLeave={handlePopoverClose}>
      <Typography
        aria-owns={open ? "mouse-over-popover" : undefined}
        aria-haspopup="true"
      >
        Hover with a Popover.
      </Typography>
      <Popover
        id="mouse-over-popover"
        className={classes.popover}
        classes={{
          paper: classes.paper
        }}
        open={open}
        anchorEl={anchorEl}
        anchorOrigin={{
          vertical: "bottom",
          horizontal: "left"
        }}
        transformOrigin={{
          vertical: "top",
          horizontal: "left"
        }}
        onClose={handlePopoverClose}
        disableRestoreFocus
      >
        <Typography>I use Popover.</Typography>
      </Popover>
    </div>
  );
}
cyej8jka

cyej8jka3#

MUI第5版
<Menu
    anchorEl={anchorEl}
    open={open}
    onClose={handleMouseLeave}
    sx={{
        pointerEvents: 'none'
    }}
    MenuListProps={{
        'aria-labelledby': 'basic-button'
    }}
    PaperProps={{
        onMouseEnter: handleMouseEnter,
        onMouseLeave: handleMouseLeave,
        sx: {
            pointerEvents: 'auto'
        }
    }}
>
    <MenuItem onClick={handleMouseLeave}>Profile</MenuItem>
    <MenuItem onClick={handleMouseLeave}>My account</MenuItem>
    <MenuItem onClick={handleMouseLeave}>Logout</MenuItem>
</Menu>
axkjgtzd

axkjgtzd4#

MUI v5中:
我搜索了很多解决方案,最简单的方法是使用"material-ui-popup-state",请确定,因为它是由MUI here引入的;
我做了一个完整的例子codesandbox

import * as React from 'react';
import Typography from '@mui/material/Typography';
import Button from '@mui/material/Button';
import PopupState, { bindTrigger, bindPopover ,bindHover } from 'material-ui-popup-state';
import HoverPopover from "material-ui-popup-state/HoverPopover";

export default function PopoverPopupState() {
    return (
        <PopupState variant="popover" popupId="demo-popup-popover">
            {(popupState) => (
                <div>
                    <Button variant="contained" {...bindHover(popupState)}>
                        Open Popover
                    </Button>
                    <HoverPopover
                        {...bindPopover(popupState)}
                        anchorOrigin={{
                            vertical: 'bottom',
                            horizontal: 'center',
                        }}
                        transformOrigin={{
                            vertical: 'top',
                            horizontal: 'center',
                        }}
                    >
                        <Typography sx={{ p: 2 }}>The content of the Popover.</Typography>
                    </HoverPopover>
                </div>
            )}
        </PopupState>
    );
}
quhf5bfb

quhf5bfb5#

MUI第5版

export const MouseOverPopover = () => {
  const [openedPopover, setOpenedPopover] = useState(false);
  const popoverAnchor = useRef(null);

  const popoverEnter = () => {
    setOpenedPopover(true);
  };

  const popoverLeave = () => {
    setOpenedPopover(false);
  };

  return (
    <>
      <Button
        aria-haspopup="true"
        onMouseEnter={popoverEnter}
        onMouseLeave={popoverLeave}
        ref={popoverAnchor}
      />

      <Popover
        open={openedPopover}
        anchorEl={popoverAnchor.current}
        sx={{
          pointerEvents: "none",
        }}
        anchorOrigin={{
          vertical: "bottom",
          horizontal: "left",
        }}
        transformOrigin={{
          vertical: "top",
          horizontal: "left",
        }}
        PaperProps={{ onMouseEnter: popoverEnter, onMouseLeave: popoverLeave }}
      >
        <Box sx={{ pointerEvents: "auto" }}>{content}</Box>
      </Popover>
    </>
  );
};
bhmjp9jg

bhmjp9jg6#

谢谢this answer。小心使用pointerEvents: 'none'pointerEvents: 'auto'才能真正工作。

pu82cl6c

pu82cl6c7#

codesandbox DEMO
我通过为onMouseLeave事件添加一个setTimeout()函数来破解它......我确信还有其他方法可以做到这一点,但这取决于您的具体需要

handlePopoverClose = () => {
    setTimeout(() => { 
      this.setState({ anchorEl: null });
    }, 3000);
  };

相关问题