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

如何在Material UI(v4)表格中实现列宽调整?(函数组件版)

Material UI v4 表格列宽调整(函数组件版)

直接上改写后的函数组件代码,逻辑和你参考的类组件完全一致,适配React函数组件的写法:

import React, { useState, useRef } from 'react';
import { Table, TableHead, TableBody, TableCell, TableRow, Paper } from '@material-ui/core';

const ResizableTable = () => {
  // 存储各列宽度,替代类组件的state
  const [columnWidths, setColumnWidths] = useState({
    name: 200,
    calories: 150,
    fat: 100,
    carbs: 100,
    protein: 100,
  });

  // 拖拽相关的引用,替代类组件的实例refs
  const resizerRefs = useRef({});
  const startX = useRef(0);
  const startWidth = useRef(0);
  const currentColumn = useRef(null);

  // 拖拽开始事件
  const handleMouseDown = (e, column) => {
    e.preventDefault();
    startX.current = e.clientX;
    startWidth.current = columnWidths[column];
    currentColumn.current = column;

    document.addEventListener('mousemove', handleMouseMove);
    document.addEventListener('mouseup', handleMouseUp);
  };

  // 拖拽过程事件
  const handleMouseMove = (e) => {
    if (!currentColumn.current) return;
    const widthDiff = e.clientX - startX.current;
    setColumnWidths(prev => ({
      ...prev,
      [currentColumn.current]: Math.max(100, startWidth.current + widthDiff) // 限制最小宽度为100px
    }));
  };

  // 拖拽结束事件
  const handleMouseUp = () => {
    document.removeEventListener('mousemove', handleMouseMove);
    document.removeEventListener('mouseup', handleMouseUp);
    currentColumn.current = null;
  };

  // 渲染带拖拽手柄的表头单元格
  const renderHeaderCell = (label, columnKey) => (
    <TableCell 
      style={{ width: columnWidths[columnKey], position: 'relative' }}
    >
      {label}
      <div
        ref={el => resizerRefs.current[columnKey] = el}
        style={{
          position: 'absolute',
          right: 0,
          top: 0,
          bottom: 0,
          width: 5,
          cursor: 'col-resize',
          backgroundColor: '#ccc',
        }}
        onMouseDown={(e) => handleMouseDown(e, columnKey)}
      />
    </TableCell>
  );

  return (
    <Paper style={{ width: '100%', overflowX: 'auto' }}>
      <Table>
        <TableHead>
          <TableRow>
            {renderHeaderCell('Name', 'name')}
            {renderHeaderCell('Calories', 'calories')}
            {renderHeaderCell('Fat (g)', 'fat')}
            {renderHeaderCell('Carbs (g)', 'carbs')}
            {renderHeaderCell('Protein (g)', 'protein')}
          </TableRow>
        </TableHead>
        <TableBody>
          <TableRow>
            <TableCell style={{ width: columnWidths.name }}>Frozen yoghurt</TableCell>
            <TableCell style={{ width: columnWidths.calories }}>159</TableCell>
            <TableCell style={{ width: columnWidths.fat }}>6.0</TableCell>
            <TableCell style={{ width: columnWidths.carbs }}>24</TableCell>
            <TableCell style={{ width: columnWidths.protein }}>4.0</TableCell>
          </TableRow>
          {/* 可自行添加更多数据行 */}
        </TableBody>
      </Table>
    </Paper>
  );
};

export default ResizableTable;

关键转换说明

  • 状态替换:用useState替代类组件的this.state,直接通过setColumnWidths更新列宽,写法更简洁。
  • 引用替换:用useRef创建拖拽相关的引用(比如起始X坐标、当前拖拽列),代替类组件中createRef生成的实例属性,避免组件重渲染时丢失引用。
  • 事件处理:拖拽的三个事件函数直接定义在组件内部,不需要像类组件那样手动绑定this,借助React闭包就能直接访问状态和引用。
  • 渲染逻辑:把表头单元格的渲染抽成renderHeaderCell函数,和原类组件的渲染逻辑完全对齐,代码结构更清晰。

内容的提问来源于stack exchange,提问作者zahra zamani

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 20:42:39