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

如何将MUI Modal居中于指定div而非整个屏幕?

问题:MUI Modal 无法在指定容器内居中,总是以屏幕为基准居中

我尝试将MUI Modal居中到class为check-mate的div容器内,但它自动居中于整个屏幕。我希望仅在该div内居中,目前无法将Modal与该div关联,求解决方法。

File.js

<React.Fragment>
      <div
        className="check-mate"
        style={{
          backgroundColor: 'red',
          position: 'relative',
        }}
      >
        <>
          <Stack
            spacing={2}
            className="absolute right-0 mt-10 mr-10"
          >
            <Fab
              id="zoom_in"
              tooltip="Zoom In"
              size="small"
              color="primary"
              aria-label="zoom-in"
            >
              <Tooltip title="Zoom In">
                <ZoomInSharpIcon />
              </Tooltip>
            </Fab>
            <Fab
              id="collapse-all"
              size="small"
              color="primary"
              aria-label="collapse-all"
              tooltip="Collapse All"
            >
              <Tooltip title="Collapse All">
                <FuseSvgIcon>material-outline:call_merge</FuseSvgIcon>
              </Tooltip>
            </Fab>
          </Stack>
          <>
            {Object.keys(props.treeData).length > 1 ? (
              <Box
                t={2}
                ref={svgRef}
                className="chart-container"
                sx={{ flexGrow: 1 }}
              />
            ) : (
              <FuseLoading />
            )}

            <PopupChart
              onClose={popupCloseHandler}
              show={visibility}
              data={popupData}
              title=""
              popupTabs={popupTabs}
              popupPosition={popupPosition}
              nodeName={nodeName}
              theme={theme}
            />
          </>
        </>
      </div>
    </React.Fragment>
import { useEffect, useState, useRef } from "react";
import popupStyles from "./Popup.module.css";
import PropTypes from "prop-types";
import CircularProgress from "@mui/material/CircularProgress";
import * as am4core from "@amcharts/amcharts4/core";
import * as am4charts from "@amcharts/amcharts4/charts";

import Backdrop from "@mui/material/Backdrop";
import Modal from "@mui/material/Modal";
import Fade from "@mui/material/Fade";
import Typography from "@mui/material/Typography";


  let margin = { top: 30, right: 50, bottom: 0, left: 100 },
    height = 320 - margin.top - margin.bottom;

  const style = {
    position: "absolute",
    top: "50%",
    left: "50%",
    transform: "translate(-50%, -50%)",
    width: 600,
    bgcolor: "background.paper",
    border: "2px solid #000",
    boxShadow: 24,
    borderRadius: "5%",
    p: 2,
    display: "flex",
    flexDirection: "column",
  };

  return (
    <div>
      <Modal
        aria-labelledby="transition-modal-title"
        aria-describedby="transition-modal-description"
        open={show}
        onClose={closeHandler}
        closeAfterTransition
        BackdropComponent={Backdrop}
        BackdropProps={{
          timeout: 500,
        }}
      >
        <Fade in={show}>
          <Box sx={style}>
            <Typography
              variant="h6"
              sx={{ textAlign: "center" }}
            >
              {nodeName}
            </Typography>
            {props.data.length > 0 ? (
              <Box sx={{ width: "100%" }}>
                <Tabs
                  value={tabValue}
                  onChange={(event, value) => setTabValue(value)}
                  textColor="secondary"
                  indicatorColor="secondary"
                  aria-label="secondary tabs example"
                  onClick={(e) => {
                    console.log("Came here 01");
                  }}
                >
                  {props.popupTabs.map((element, i) => (
                    <Tab
                      key={element}
                      onClick={(e) => {
                        console.log("Came here");
                        setActiveTab(element);
                      }}
                      label={element}
                      value={element}
                    />
                  ))}
                </Tabs>
                {
                  <Box
                    id="popup_chart"
                    sx={{
                      height: height + margin.top + margin.bottom + "px",
                      alignItems: "center",
                    }}
                    className="svgWrapper"
                  ></Box>
                }
              </Box>
            ) : (
              <Typography
                variant="p"
                gutterBottom
                component="div"
                sx={{ textAlign: "center" }}
              >
                No Drills available for this node
              </Typography>
            )}

            {loading && (
              <Box
                sx={{
                  display: "flex",
                  flexGrow: 1,
                  justifyContent: "center",
                  alignItems: "center",
                  position: "absolute",
                  top: "50%",
                  right: "50%",
                }}
              >
                <CircularProgress color="success" />
              </Box>
            )}
          </Box>
        </Fade>
      </Modal>
    </div>
  );

当前效果:
当前效果


解决方法

MUI Modal默认基于整个视口定位,要让它在指定容器内居中,需修改两个核心设置:

  • 关联目标容器:给Modal指定父容器,让它挂载到目标div内部而非body下
  • 调整定位样式:修改Modal和内容框的定位规则,使其相对于目标容器居中

步骤1:给目标容器添加Ref并传递给Modal组件

修改File.js,为check-mate容器创建ref,并将其传递给PopupChart组件:

import { useRef } from 'react';

// 在组件内部创建容器ref
const containerRef = useRef(null);

<React.Fragment>
  <div
    className="check-mate"
    ref={containerRef} // 绑定ref
    style={{
      backgroundColor: 'red',
      position: 'relative', // 必须保留,作为绝对定位的基准容器
    }}
  >
    {/* 其他内容不变 */}
    <PopupChart
      onClose={popupCloseHandler}
      show={visibility}
      data={popupData}
      title=""
      popupTabs={popupTabs}
      popupPosition={popupPosition}
      nodeName={nodeName}
      theme={theme}
      containerRef={containerRef} // 传递ref给Modal组件
    />
  </div>
</React.Fragment>

步骤2:修改Modal组件的容器关联与样式

更新Modal.js,接收传入的ref,指定Modal的父容器,并调整定位样式:

// 接收props中的containerRef
const PopupChart = ({ containerRef, show, closeHandler, ...props }) => {
  let margin = { top: 30, right: 50, bottom: 0, left: 100 },
    height = 320 - margin.top - margin.bottom;

  const style = {
    position: "absolute",
    top: "50%",
    left: "50%",
    transform: "translate(-50%, -50%)",
    width: 600,
    bgcolor: "background.paper",
    border: "2px solid #000",
    boxShadow: 24,
    borderRadius: "5%",
    p: 2,
    display: "flex",
    flexDirection: "column",
  };

  return (
    <div>
      <Modal
        container={containerRef.current} // 指定Modal的父容器
        aria-labelledby="transition-modal-title"
        aria-describedby="transition-modal-description"
        open={show}
        onClose={closeHandler}
        closeAfterTransition
        BackdropComponent={Backdrop}
        BackdropProps={{
          timeout: 500,
        }}
        // 让Modal占满整个目标容器
        sx={{
          position: 'absolute',
          top: 0,
          left: 0,
          width: '100%',
          height: '100%',
        }}
      >
        <Fade in={show}>
          <Box sx={style}>
            {/* Modal内部内容保持不变 */}
          </Box>
        </Fade>
      </Modal>
    </div>
  );
};

// 添加propTypes校验
PopupChart.propTypes = {
  containerRef: PropTypes.object.isRequired,
  // 其他propTypes...
};

export default PopupChart;

关键说明

  1. 目标容器check-mate必须设置position: relative,否则内部绝对定位元素会向上寻找第一个定位父元素
  2. Modal的container属性会将Modal的根节点挂载到指定容器内部,替代默认的body挂载
  3. 给Modal添加的sx样式让它占满目标容器,确保遮罩层(Backdrop)覆盖整个容器而非屏幕
  4. 内容框的top:50% + left:50% + transform: translate(-50%,-50%)是标准的绝对定位居中方案

内容的提问来源于stack exchange,提问作者Jamal Butt

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 20:06:51