You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 21:35:20