基于 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. 样式隔离:通过容器类名限制样式作用域,防止全局污染
相关推荐
孤╮独的美几秒前
CSS3:深度解析与实战应用
前端·css·css3
一城烟雨_9 分钟前
Vue3 实现pdf预览
前端·vue.js·pdf
易xingxing13 分钟前
探索HTML5 Canvas:创造动态与交互性网页内容的强大工具
前端·html·html5
好_快22 分钟前
Lodash源码阅读-arrayPush
前端·javascript·源码阅读
好_快24 分钟前
Lodash源码阅读-equalByTag
前端·javascript·源码阅读
大土豆的bug记录5 小时前
鸿蒙进行视频上传,使用 request.uploadFile方法
开发语言·前端·华为·arkts·鸿蒙·arkui
maybe02095 小时前
前端表格数据导出Excel文件方法,列自适应宽度、增加合计、自定义文件名称
前端·javascript·excel·js·大前端
HBR666_5 小时前
菜单(路由)权限&按钮权限&路由进度条
前端·vue
A-Kamen6 小时前
深入理解 HTML5 Web Workers:提升网页性能的关键技术解析
前端·html·html5
锋小张7 小时前
a-date-picker 格式化日期格式 YYYY-MM-DD HH:mm:ss
前端·javascript·vue.js