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

Material UI如何创建带行列标题的5×4输入表格?

问题描述

我想用Material UI创建一个带行标题、列标题的5×4输入表格,预期效果参考指定图片(示例为5×3,需调整为5×4)。但当前代码存在两个问题:

  1. 布局不符合预期
  2. 输入umaValues[0][0]时整列会同步变化

以下是我的代码片段:

<Grid item xs={12}>
  <Grid container spacing={2}>
    <Grid item xs={3}>
      <FormControl>
        <FormLabel>1st Place</FormLabel>
        <TextField variant="outlined" type="number" value={umaValues[0][0]} onChange={handleUmaChange(0, 0)} />
      </FormControl>
    </Grid>
    <Grid item xs={3}>
      <FormControl>
        <FormLabel>2nd Place</FormLabel>
        <TextField variant="outlined" type="number" value={umaValues[0][1]} onChange={handleUmaChange(0, 1)} />
      </FormControl>
    </Grid>
    <Grid item xs={3}>
      <FormControl>
        <FormLabel>3rd Place</FormLabel>
        <TextField variant="outlined" type="number" value={umaValues[0][2]} onChange={handleUmaChange(0, 2)} />
      </FormControl>
    </Grid>
    <Grid item xs={3}>
      <FormControl>
        <FormLabel>4th Place</FormLabel>
        <TextField variant="outlined" type="number" value={umaValues[0][3]} onChange={handleUmaChange(0, 3)} />
      </FormControl>
    </Grid>
  </Grid>
  <Grid container spacing={2}>
    <Grid item xs={3}>
      <FormControl>
        <FormLabel>Uma 0 Over</FormLabel>
        <TextField variant="outlined" type="number" value={umaValues[1][0]} onChange={handleUmaChange(1, 0)} />
      </FormControl>
    </Grid>
    <Grid item xs={3}>
      <FormControl>
        <FormLabel>Uma 1 Over</FormLabel>
        <TextField variant="outlined" type="number" value={umaValues[1][1]} onChange={handleUmaChange(1, 1)} />
      </FormControl>
    </Grid>
    <Grid item xs={3}>
      <FormControl>
        <FormLabel>Uma 2 Over</FormLabel>
        <TextField variant="outlined" type="number" value={umaValues[1][2]} onChange={handleUmaChange(1, 2)} />
      </FormControl>
    </Grid>
    <Grid item xs={3}>
      <FormControl>
        <FormLabel>Uma 3 Over</FormLabel>
        <TextField variant="outlined" type="number" value={umaValues[1][3]} onChange={handleUmaChange(1, 3)} />
      </FormControl>
    </Grid>
  </Grid>
  <Grid container spacing={2}>
    <Grid item xs={3}>
      <FormControl>
        <FormLabel>Uma 4 Over</FormLabel>
        <TextField variant="outlined" type="number" value={umaValues[2][0]} onChange={handleUmaChange(2, 0)} />
      </FormControl>
    </Grid>
    <Grid item xs={3}>
      <FormControl>
        <FormLabel></FormLabel>
        <TextField variant="outlined" type="number" value={umaValues[2][1]} onChange={handleUmaChange(2, 1)} />
      </FormControl>
    </Grid>
    <Grid item xs={3}>
      <FormControl>
        <FormLabel></FormLabel>
        <TextField variant="outlined" type="number" value={umaValues[2][2]} onChange={handleUmaChange(2, 2)} />
      </FormControl>
    </Grid>
    <Grid item xs={3}>
      <FormControl>
        <FormLabel></FormLabel>
        <TextField variant="outlined" type="number" value={umaValues[2][3]} onChange={handleUmaChange(2, 3)} />
      </FormControl>
    </Grid>
  </Grid>
  <Grid container spacing={2}>
    <Grid item xs={3}>
      <FormControl>
        <FormLabel></FormLabel>
        <TextField variant="outlined" type="number" value={umaValues[3][0]} onChange={handleUmaChange(3, 0)} />
      </FormControl>
    </Grid>
    <Grid item xs={3}>
      <FormControl>
        <FormLabel></FormLabel>
        <TextField variant="outlined" type="number" value={umaValues[3][1]} onChange={handleUmaChange(3, 1)} />
      </FormControl>
    </Grid>
    <Grid item xs={3}>
      <FormControl>
        <FormLabel></FormLabel>
        <TextField variant="outlined" type="number" value={umaValues[3][2]} onChange={handleUmaChange(3, 2)} />
      </FormControl>
    </Grid>
    <Grid item xs={3}>
      <FormControl>
        <FormLabel></FormLabel>
        <TextField variant="outlined" type="number" value={umaValues[3][3]} onChange={handleUmaChange(3, 3)} />
      </FormControl>
    </Grid>
  </Grid>
</Grid>
解决方案

1. 修复整列同步变化的问题

整列同步变化的核心原因是**handleUmaChange写法错误**:直接调用handleUmaChange(0,0)会导致组件渲染时就执行该函数,且同列输入框共享了同一状态更新逻辑。正确写法是让handleUmaChange返回一个函数,而非直接执行。

修改后的handleUmaChange示例:

const handleUmaChange = (row, col) => (e) => {
  const newValue = Number(e.target.value);
  // 深拷贝原数组,避免直接修改状态
  const newUmaValues = umaValues.map(rowArr => [...rowArr]);
  newUmaValues[row][col] = newValue;
  setUmaValues(newUmaValues);
};

注意:必须深拷贝二维数组,否则React无法检测到状态变化,导致输入框值不更新。直接修改umaValues[row][col]属于修改原状态对象,React不会触发重渲染。

2. 调整布局实现标准行列标题结构

当前代码把列标题放在第一行的FormLabel里,行标题分散在各行第一列,布局逻辑混乱。重构为表头行+数据行的结构,每一行包含一个行标题单元格和4个输入单元格:

import { Grid, FormControl, FormLabel, TextField } from '@mui/material';
import { useState } from 'react';

// 定义行列标题数据
const columnTitles = ['1st Place', '2nd Place', '3rd Place', '4th Place'];
const rowTitles = ['Uma 0 Over', 'Uma 1 Over', 'Uma 2 Over', 'Uma 3 Over', 'Uma 4 Over']; // 5行标题

export default function UmaTable() {
  // 初始化状态:5行4列的二维数组,初始值设为0
  const [umaValues, setUmaValues] = useState(
    Array(5).fill().map(() => Array(4).fill(0))
  );

  // 正确的状态更新函数
  const handleUmaChange = (row, col) => (e) => {
    const newValue = Number(e.target.value);
    const newUmaValues = umaValues.map(r => [...r]);
    newUmaValues[row][col] = newValue;
    setUmaValues(newUmaValues);
  };

  return (
    <Grid container spacing={2} sx={{ mt: 2 }}>
      {/* 表头行:第一列为空占位,后面是4个列标题 */}
      <Grid item xs={12}>
        <Grid container spacing={2}>
          <Grid item xs={3} />
          {columnTitles.map((title, col) => (
            <Grid item xs={3} key={col}>
              <FormLabel sx={{ fontWeight: 'bold', textAlign: 'center', display: 'block' }}>
                {title}
              </FormLabel>
            </Grid>
          ))}
        </Grid>
      </Grid>

      {/* 数据行:每行包含一个行标题 + 4个输入框 */}
      {rowTitles.map((title, row) => (
        <Grid item xs={12} key={row}>
          <Grid container spacing={2}>
            {/* 行标题单元格 */}
            <Grid item xs={3}>
              <FormLabel sx={{ textAlign: 'right', display: 'flex', alignItems: 'center', height: '100%' }}>
                {title}
              </FormLabel>
            </Grid>
            {/* 4个输入框单元格 */}
            {Array(4).fill().map((_, col) => (
              <Grid item xs={3} key={col}>
                <FormControl fullWidth>
                  <TextField
                    variant="outlined"
                    type="number"
                    value={umaValues[row][col]}
                    onChange={handleUmaChange(row, col)}
                  />
                </FormControl>
              </Grid>
            ))}
          </Grid>
        </Grid>
      ))}
    </Grid>
  );
}

布局调整说明:

  • 用Grid构建完整表格结构,第一行是列标题,后续每行是行标题+输入框
  • 行标题固定在每行左侧,列标题固定在顶部
  • 使用循环渲染代替重复代码,更易维护,避免手动编写重复的Grid项
  • 通过sx样式调整标题对齐方式,让布局更规整

内容的提问来源于stack exchange,提问作者Vincent Zheng

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 10:20:46