基于 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. 样式隔离:通过容器类名限制样式作用域,防止全局污染
相关推荐
m0_738120728 分钟前
CTFshow系列——命令执行web38-40
前端·windows·安全·web安全
是小狐狸呀2 小时前
elementUI-表单-下拉框数据选中后,视图不更新
前端·javascript·elementui
四岁半儿4 小时前
常用css
前端·css
你的人类朋友5 小时前
说说git的变基
前端·git·后端
姑苏洛言5 小时前
网页作品惊艳亮相!这个浪浪山小妖怪网站太治愈了!
前端
字节逆旅5 小时前
nvm 安装pnpm的异常解决
前端·npm
Jerry5 小时前
Compose 从 View 系统迁移
前端
GIS之路6 小时前
2025年 两院院士 增选有效候选人名单公布
前端
四岁半儿6 小时前
vue,H5车牌弹框定制键盘包括新能源车牌
前端·vue.js
烛阴6 小时前
告别繁琐的类型注解:TypeScript 类型推断完全指南
前端·javascript·typescript