基于 React-Resizable 的 ProTable 表格列宽拖拽实践

技术背景

本方案将演示如何构建可复用的高阶ProTable表格列拖拽组件,并提供完整的样式优化指南。

技术实现路径

1. 环境准备
csharp 复制代码
# 使用任意包管理器安装核心依赖
yarn add react-resizable
# 或
npm install react-resizable --save
2. 构建高阶组件

创建ResizableTable.jsx实现拖拽逻辑封装:

ini 复制代码
import React, { useEffect, useState } from 'react';
import { Resizable } from 'react-resizable';
import { ProTable } from '@ant-design/pro-components';
import './index.less';

/**
 * 可伸缩表头单元格组件
 * @param {Object} props - 组件属性
 * @param {Function} props.onResize - 列宽调整时的回调函数
 * @param {number} props.width - 列的宽度
 */
const ResizableTitle = (props) => {
  const { onResize, width, ...restProps } = props;

  // 如果未提供宽度,则使用普通表头单元格
  if (!width) {
    return <th {...restProps} />;
  }

  return (
    <Resizable
      width={width}
      height={0}
      handle={
        <span
          className="react-resizable-handle"
          onClick={(e) => {
            // 阻止事件冒泡和默认行为
            e.stopPropagation();
            e.preventDefault();
          }}
        />
      }
      onResize={onResize}
      draggableOpts={{ enableUserSelectHack: false }}
    >
      <th {...restProps} />
    </Resizable>
  );
};

/**
 * ProTable 可伸缩列组件
 * @param {Object} props - ProTable 的属性
 * @param {Array} props.columns - 表格列配置
 */
const ResizableTable = (props) => {
  const [columns, setColumns] = useState([]);

  // 当传入的 columns 发生变化时,更新本地 columns 状态
  useEffect(() => {
    if (props.columns) {
      setColumns(props.columns);
    }
  }, [props.columns]);

  /**
   * 处理列宽调整的回调函数
   * @param {number} index - 列的索引
   * @returns {Function} - 列宽调整时的实际处理函数
   */
  const handleResize = (index) => (_, { size }) => {
    const newColumns = [...columns];
    newColumns[index] = {
      ...newColumns[index],
      width: size.width,
    };
    setColumns(newColumns);
  };

  const mergeColumns = columns.map((col, index) => ({
    ...col,
    onHeaderCell: (column) => ({
      // 如果未提供列宽,默认使用 80
      width: column.width || 80, 
      onResize: handleResize(index),
    }),
  }));

  return (
    <div className="resizeTable">
      <ProTable
        {...props}
        components={{
          header: {
            cell: ResizableTitle,
          },
        }}
        scroll={{ x: 900 }}
        columns={mergeColumns}
      />
    </div>
  );
};

export default ResizableTable;
    
3. 业务组件集成
ini 复制代码
import ResizableTable from '@/components/ResizableTable';

const BusinessComponent = () => {
  // 列配置需包含精确宽度
  const columns = [
    { title: '区域机构', dataIndex: 'orgName', width: 200 },
    { title: '传片数', dataIndex: 'uploads', width: 80 },
    { title: 'AI阳性率', dataIndex: 'positiveRate', width: 120 },
  ];

  return (
    <div className="data-container">
      <ResizableTable
        size="small"
        rowKey="id"
        columns={columns}
        dataSource={dataset}
        pagination={{ pageSize: 50 }}
      />
    </div>
  );
};
4. 样式优化方案
css 复制代码
.resizeTable {
  .react-resizable {
    position: relative;
    background-clip: padding-box;
    user-select: none;
  }

  // 防止默认出现横向滚动条
  .ant-table-content > table {
    min-width: calc(100% - 5px) !important;
  }

  .react-resizable-handle {
    position: absolute;
    width: 10px;
    height: 100%;
    bottom: 0;
    right: -5px;
    cursor: col-resize;
    background-image: none;
    z-index: 1;
  }
}

方案优势

  1. 逻辑解耦:将拖拽逻辑封装为独立高阶组件,实现业务零侵入
  2. 精准控制:要求列定义必须包含数值型 width 属性,避免渲染抖动
  3. 样式隔离:通过容器类名限制样式作用域,防止全局污染
相关推荐
子兮曰2 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰2 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万2 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝2 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋2 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁2 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
汉堡大王95272 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大2 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师2 天前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端
沙蒿同学2 天前
我用 Go 搭了一条 AI Agent 流水线:从 1 张商品图到一整套淘宝详情页
前端·javascript·后端