React MUI Popper鼠标悬停激活后移至弹窗消失无法点击链接问题
解决MUI Popper鼠标移到弹窗时立即消失的问题
问题原因
触发元素和Popper是同级DOM元素,鼠标从触发元素移向Popper时,触发元素的mouseOut事件会先触发,此时Popper的mouseOver事件还未执行,导致弹窗被提前关闭。同时你当前的inBox状态存在时序问题:触发元素的mouseOut执行时,Popper的mouseOver还没触发,inBox仍为false,无法阻止弹窗关闭。
解决方案
通过延迟关闭+状态联动处理,核心逻辑是:鼠标离开触发元素时不立即关闭弹窗,等待一小段时间,若这段时间内鼠标进入Popper则取消关闭;若未进入再执行关闭。同时统一管理弹窗状态,确保鼠标在触发元素或Popper上时弹窗保持打开。
修改后的代码示例
import "./styles.css"; import React, { useState, useRef } from "react"; import { Box, Popper } from "@mui/material"; export default function App() { const [anchorEl, setAnchorEl] = useState<(EventTarget & Element) | null>(null); const closeTimerRef = useRef<NodeJS.Timeout | null>(null); // 打开弹窗,清除之前的关闭定时器 const handleOpen = (e: React.MouseEvent) => { if (closeTimerRef.current) { clearTimeout(closeTimerRef.current); } setAnchorEl(e.currentTarget); }; // 触发延迟关闭弹窗的操作 const handleTriggerLeave = () => { closeTimerRef.current = setTimeout(() => { setAnchorEl(null); }, 200); // 200ms延迟,可根据需求调整 }; // 鼠标进入弹窗时,取消关闭操作 const handlePopperEnter = () => { if (closeTimerRef.current) { clearTimeout(closeTimerRef.current); } }; // 鼠标离开弹窗时,直接关闭弹窗 const handlePopperLeave = () => { setAnchorEl(null); }; const open = !!anchorEl; return ( <Box> <Box component="div" sx={{ backgroundColor: "red", width: "100px", height: "100px" }} onMouseEnter={handleOpen} onMouseLeave={handleTriggerLeave} /> {open && ( <Popper open={open} anchorEl={anchorEl} placement="bottom-start"> <Box sx={{ backgroundColor: "green", width: "170px", height: "70px", padding: "10px" }} onMouseEnter={handlePopperEnter} onMouseLeave={handlePopperLeave} > {/* 可添加需要点击的链接 */} <a href="#link1">链接1</a> <a href="#link2" style={{ marginLeft: "10px" }}>链接2</a> </Box> </Popper> )} <Box onMouseEnter={handleOpen} onMouseLeave={handleTriggerLeave} sx={{ backgroundColor: "blue", width: "100px", height: "100px" }} /> </Box> ); }
代码说明
- 用
useRef保存关闭定时器的引用,确保能在需要时清除定时器,避免重复触发关闭。 - 替换
onMouseOver/onMouseOut为onMouseEnter/onMouseLeave,这类事件只会在鼠标进入/离开整个元素时触发,不会因为子元素频繁触发,更适合处理整体hover状态。 - Popper内的
onMouseEnter清除关闭定时器,确保弹窗保持打开;onMouseLeave直接关闭弹窗,符合正常交互逻辑。
内容的提问来源于stack exchange,提问作者GRZa
相关产品推荐
相关产品推荐

