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

基于Material UI封装方法实现Box布局:3个一排且第4个叠于首个下方

问题描述

本人是Material UI、TypeScript和React新手,若表述有误或术语使用不当请予以指正。我需要在页面上布局4个Box,要求其中3个横向排成一行,第4个堆叠在第一个Box的下方。

目前我使用Grid容器作为父组件来包裹这些Box,代码如下:

<Grid container={true} spacing={1} justifyContent="center" alignItems='flex-start'>
    <Box sx={{m: 1}} style={{width: '500px', height: '600px'}}>
      <SomeData data={defaultDeploymentFrequencyData}/>
    </Box>
    <Box sx={{m: 1}} style={{width: '500px', height: '600px'}}>
      <SomeData data={defaultDeploymentFrequencyData}/>
    </Box>
    <Box sx={{m: 1}} style={{width: '500px', height: '600px'}}>
      <SomeData data={defaultDeploymentFrequencyData}/>
    </Box>
    <Box sx={{m: 1}} style={{width: '500px', height: '600px'}}>
      <SomeData data={defaultDeploymentFrequencyData}/>
    </Box>
  </Grid>

我不想重复编写Box代码,希望通过调用一个方法来实现正确的布局。我尝试编写了如下BoxLayout组件:

export const BoxLayout = ():JSX.Element => {
  return (
    <Box>
      sx={{
        display: 'grid',
        gap: 1,
        gridTemplateColumns: 'repeat(2, 1fr)',
      }}
    </Box>
  )
}

并设想了如下调用方式:

<Grid container={true} spacing={1} justifyContent="center" alignItems='flex-start'>
  <BoxLayout>
   <SomeData data={defaultDeploymentFrequencyData}/>
   <SomeData data={defaultDeploymentFrequencyData}/>
   <SomeData data={defaultDeploymentFrequencyData}/>
   <SomeData data={defaultDeploymentFrequencyData}/>
  </BoxLayout>
</Grid>

请问该如何正确实现这种布局调用?

解决方案

1. 修正现有BoxLayout的问题

你的BoxLayout存在两个核心错误:

  • sx属性被错误地写在Box标签内部,应该作为props传递给Box
  • 没有接收并渲染子组件(children),导致传入的SomeData无法显示

2. 实现符合需求的布局组件

下面提供两种适配需求的实现方式,都能实现3个Box横向一行,第4个堆叠在第一个下方的效果,同时复用Box的样式代码:

方式一:基于Material UI Grid系统实现

贴合你最初的思路,利用MUI Grid的栅格逻辑拆分布局:

import { Box, Grid } from '@mui/material';
import { ReactNode } from 'react';

interface BoxLayoutProps {
  children: ReactNode[];
}

export const BoxLayout = ({ children }: BoxLayoutProps): JSX.Element => {
  return (
    <Grid container spacing={1} justifyContent="center" alignItems="flex-start">
      {/* 第一列:放置第1、4个Box */}
      <Grid item>
        {children.slice(0, 1).map((child, idx) => (
          <Box key={idx} sx={{ m: 1, width: '500px', height: '600px' }}>
            {child}
          </Box>
        ))}
        {children.slice(3, 4).map((child, idx) => (
          <Box key={idx + 1} sx={{ m: 1, width: '500px', height: '600px' }}>
            {child}
          </Box>
        ))}
      </Grid>
      {/* 第二、三列:分别放置第2、3个Box */}
      {children.slice(1, 3).map((child, idx) => (
        <Grid item key={idx + 2}>
          <Box sx={{ m: 1, width: '500px', height: '600px' }}>
            {child}
          </Box>
        </Grid>
      ))}
    </Grid>
  );
};

调用方式:

<BoxLayout>
  <SomeData data={defaultDeploymentFrequencyData}/>
  <SomeData data={defaultDeploymentFrequencyData}/>
  <SomeData data={defaultDeploymentFrequencyData}/>
  <SomeData data={defaultDeploymentFrequencyData}/>
</BoxLayout>

方式二:基于CSS Grid实现

用纯CSS Grid的区域定义来控制布局,代码更简洁:

import { Box } from '@mui/material';
import { ReactNode } from 'react';

interface BoxLayoutProps {
  children: ReactNode[];
}

export const BoxLayout = ({ children }: BoxLayoutProps): JSX.Element => {
  return (
    <Box
      sx={{
        display: 'grid',
        gap: 1,
        // 定义网格区域,明确每个Box的位置
        gridTemplateAreas: `
          "box1 box2 box3"
          "box4 box2 box3"
        `,
        justifyContent: 'center',
        padding: 1,
      }}
    >
      {children.map((child, idx) => (
        <Box
          key={idx}
          sx={{
            m: 1,
            width: '500px',
            height: '600px',
            gridArea: idx === 0 ? 'box1' : idx === 1 ? 'box2' : idx === 2 ? 'box3' : 'box4',
          }}
        >
          {child}
        </Box>
      ))}
    </Box>
  );
};

调用方式和上述一致,直接传入4个SomeData组件即可。

3. 核心说明

  • 两种方式都实现了Box样式的复用,避免重复代码
  • 通过接收children动态渲染内容,符合React组件复用逻辑
  • 后续调整Box样式时,只需修改BoxLayout中的sx属性即可

内容的提问来源于stack exchange,提问作者Max Bojorquez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 17:21:07