如何在React.js中创建多个MUI Popover?新手技术求助
解决MUI多个Popover互相覆盖的问题
问题根源
你当前只维护了一个anchorEl状态变量,所有Popover组件都依赖这个状态控制显示/隐藏。当点击第二个触发元素时,anchorEl会被更新为新的DOM节点,第一个Popover的锚点变为null,导致它自动关闭,视觉上就出现了“被覆盖”的效果。
解决方案:为每个Popover维护独立状态
需要用对象或数组存储每个Popover的锚点元素,让每个Popover拥有独立的状态管理。以下是具体修改方案:
1. 修改状态定义
把单个anchorEl改为对象anchorEls,用唯一id作为键存储对应Popover的锚点元素:
const [anchorEls, setAnchorEls] = React.useState({});
2. 改造事件处理函数
将handleClick和handleClose改成高阶函数,接收Popover的唯一id,针对性更新对应状态:
// 打开指定id的Popover const handleClick = (popoverId) => (event) => { setAnchorEls(prevState => ({ ...prevState, [popoverId]: event.currentTarget })); }; // 关闭指定id的Popover const handleClose = (popoverId) => () => { setAnchorEls(prevState => ({ ...prevState, [popoverId]: null })); };
3. 渲染多个独立的Popover
每个Popover绑定对应的id、状态和事件处理函数,示例代码如下:
import * as React from 'react'; import { Popover, Button } from '@mui/material'; export default function Projects() { const [anchorEls, setAnchorEls] = React.useState({}); const handleClick = (popoverId) => (event) => { setAnchorEls(prevState => ({ ...prevState, [popoverId]: event.currentTarget })); }; const handleClose = (popoverId) => () => { setAnchorEls(prevState => ({ ...prevState, [popoverId]: null })); }; return ( <div style={{ display: 'flex', gap: '16px', padding: '20px' }}> {/* 第一个Popover */} <Button variant="contained" onClick={handleClick('popover1')}> 打开Popover 1 </Button> <Popover id="popover1" open={Boolean(anchorEls.popover1)} anchorEl={anchorEls.popover1} onClose={handleClose('popover1')} anchorOrigin={{ vertical: 'bottom', horizontal: 'left', }} > <p>Popover 1 的内容</p> </Popover> {/* 第二个Popover */} <Button variant="contained" onClick={handleClick('popover2')}> 打开Popover 2 </Button> <Popover id="popover2" open={Boolean(anchorEls.popover2)} anchorEl={anchorEls.popover2} onClose={handleClose('popover2')} anchorOrigin={{ vertical: 'bottom', horizontal: 'left', }} > <p>Popover 2 的内容</p> </Popover> </div> ); }
动态生成Popover的场景
如果你的Popover是从数组循环生成的,可直接用数组项的唯一标识作为id:
const projectList = [ { id: 'proj1', name: '项目A', detail: '项目A的详细信息' }, { id: 'proj2', name: '项目B', detail: '项目B的详细信息' } ]; // 渲染部分 return ( <div style={{ padding: '20px' }}> {projectList.map(project => ( <div key={project.id} style={{ marginBottom: '12px' }}> <Button variant="outlined" onClick={handleClick(project.id)}> {project.name} </Button> <Popover id={project.id} open={Boolean(anchorEls[project.id])} anchorEl={anchorEls[project.id]} onClose={handleClose(project.id)} anchorOrigin={{ vertical: 'bottom', horizontal: 'left', }} > <p>{project.detail}</p> </Popover> </div> ))} </div> );
核心逻辑说明
每个Popover通过唯一id绑定独立的锚点状态,更新或关闭时只会修改对应id的状态值,不会影响其他Popover的显示状态,从而避免了互相覆盖的问题。
内容的提问来源于stack exchange,提问作者elena
相关产品推荐
相关产品推荐

