antd table表头拖拽实现

17 篇文章 0 订阅


前言

按需求我们需要把antd库中table表格的表头,设置为可拖拽的,在antd中并没有现成的属性方法,所以我们需要用到第三方库react-resizable

本文还封装了可拖拽表头的表格组件,其中有阻止冒泡防止拖拽时引起排序、选中文字等操作。如果你急需此功能,那么可以直接滑倒底部拿取代码


一、安装 antd、react-resizable 第三方库

yarn add antd react-resizable --save

二、使用步骤

1、引入库

代码如下:

import React, { useState } from 'react'
import { Table } from 'antd'
import { Resizable } from 'react-resizable'
import "react-resizable/css/styles.css"  // 一定要引入样式,否则没有拖拽的小标
// 当然我们也可以不引入,使用自定义拖拽标标,请看下面详情

2、配置

2.1、配置表头拉伸组件:

需要放在组件外部,否则每次拖拽无法更新!

// 可伸缩表头组件,放到组件外
const ResizableTitle = ({ onResize, width, ...restProps }) => {
    if (!width) { return (<th {...restProps} />) };

    return (
        <Resizable
            width={width}
            height={0}
            handle={
                <span
                    className="react-resizable-handle"
                    onClick={e => { e.stopPropagation() }}
                />
            }
            onResize={onResize}
            draggableOpts={{ enableUserSelectHack: false }}
        >
            <th {...restProps} style={{ ...restProps?.style, userSelect: 'none' }} />
        </Resizable>
    );
};

2.2、配置表格列columns:

// 表格数据
const dataSource = [
    { _id: 1, label: '范德萨1', gender: '男' },
    { _id: 2, label: '范德萨2', gender: '女' },
    { _id: 3, label: '范德萨3', gender: '男' },
    { _id: 4, label: '范德萨4', gender: '男' },
    { _id: 5, label: '范德萨5', gender: '女' },
]

// 表格列
const columns = [
    {
        title: '#',
        dataIndex: '_id',
        width: 60,
        ellipsis: true,
    },
    {
        title: '名称',
        dataIndex: 'label',
        width: 200,
        ellipsis: true,
    },
    {
        title: '性别',
        dataIndex: 'gender',
        width: 200,
        ellipsis: true,
    },
    {
        title: '操作',
        key: 'action',
       	// width: 200,
        ellipsis: true,
        render: () => (
            <a>修改</a>
        ),
    },
];

表格列的最后一列不要设置宽度,否则会引起拉伸就会触发以下异常!。

请添加图片描述

2.3、重新配置表格列,给予拉伸的方法:

// 可伸缩表头组件
const [column, setColumn] = useState(
    columns.map(it => {
      it.ellipsis = {
        showTitle: true
      }
      it.onHeaderCell = col => ({
        width: col.width,
        // !传入newColumn,而不传入column是因为需要拿到有onHeaderCell的值,外面collumn的变化内部监听不到
        onResize: (e, { size }) => handleResize(col, size),
      })
      return it;
    }
    )
  );

2.4、拉伸回调方法:

// table的th实时宽度拖拽的改变
  const handleResize = (col, size) => {
    setColumn(column.map(item => {
      // 如果这个判断对不上,列宽可以移动但是会引起错乱
      if (item.dataIndex === col.dataIndex) {
        item.width = size.width;
      }
      return item
    }))
  }

2.5、自定义拖拽标志

在css或less中设置对应的类名样式,也可以设置为自定义的拖拽图标

// 取消引入样式,通过设置类名,来设置拖拽的标志
.react-resizable-handle {
  	position: absolute;
  	right: -5px;
  	bottom: 0;
  	z-index: 1;
  	width: 10px;
  	height: 100%;
  	cursor: col-resize;
}

3、配置table组件

// table的th实时宽度拖拽的改变
 <Table 
 	rowKey={'_id'}
  	columns={column}
  	dataSource={dataSource}
  	components={{
    	header: {
      		cell: ResizableTitle,
     	},
  	}}
 ></Table>

三、效果

请添加图片描述

拆分组件

直接拿代码
components/ResizableTableModel/index.jsx

// components/ResizableTableModel/index.jsx
// 可拖拽表格组件
import { useState } from 'react';
import { Table } from 'antd';
import { Resizable } from 'react-resizable';
import './index.css';


// 表头拖拽组件
const ResizableTitle = ({ onResize, width, ...restProps }) => {
    if (!width) { return (<th {...restProps} />) };

    return (
        <Resizable
            width={width}
            height={0}
            handle={
                <span
                    className="react-resizable-handle"
                    onClick={e => { e.stopPropagation() }}
                />
            }
            onResize={onResize}
            draggableOpts={{ enableUserSelectHack: false }}
        >
            <th {...restProps} style={{ ...restProps?.style, userSelect: 'none' }} />
        </Resizable>
    );
};


// 带拖拽表格组件
const ResizableTable = ({ columns = [], ...props }) => {
  
    // * 列数据
    const [cols, setCols] = useState(columns);
    const colsArray = cols.map((col, index) => {
        return {
            ...col,
            onHeaderCell: column => ({ width: column.width, onResize: handleResize(index) })
        };
    });

    // todo 调整列宽
    const handleResize = index => {
        return (_, { size }) => {
            const temp = [...cols];
            temp[index] = { ...temp[index], width: size.width };
            setCols(temp);
        };
    };

    return (
        <Table
            components={{ header: { cell: ResizableTitle } }}
            columns={colsArray}
            {...props}
        />
    );
};

export default ResizableTable;

components/ResizableTableModel/index.css

// components/ResizableTableModel/index.css
.react-resizable-handle {
  	position: absolute;
  	right: -5px;
  	bottom: 0;
  	z-index: 1;
  	width: 10px;
  	height: 100%;
  	cursor: col-resize;
}

pages/home/index.jsx

// pages/home/index.jsx
import React from 'react'
import { Divider, Table } from 'antd'
import ResizeableTableModel from '@/components/ResizeableTableModel'


const dataSource = [
    { _id: 1, label: '范德萨1', gender: '男' },
    { _id: 2, label: '范德萨2', gender: '女' },
    { _id: 3, label: '范德萨3', gender: '男' },
    { _id: 4, label: '范德萨4', gender: '男' },
    { _id: 5, label: '范德萨5', gender: '女' },
]


const columns = [
    {
        title: '#',
        dataIndex: '_id',
        width: 60,
        ellipsis: true,
    },
    {
        title: '名称',
        dataIndex: 'label',
        width: 200,
        ellipsis: true,
    },
    {
        title: '性别',
        dataIndex: 'gender',
        width: 200,
        ellipsis: true,
    },
    {
        title: '操作',
        key: 'action',
        width: 200,
        ellipsis: true,
        render: () => (
            <a>修改</a>
        ),
    },
];



const Layout = () => {
    return (
        <>
             <Divider children="组件表格" />
             <ResizeableTableModel
                  rowKey={'_id'}
                  columns={columns}
                  dataSource={dataSource}
              />
        </>
    )
}

export default Layout

总结

要注意以下两点:

  • 1、初始列的宽度设置
  • 2、拖拽回调的判断赋值

制作不易,看完给小编点个赞吧!

  • 9
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
怎么实现? 对于这个问题,可以使用 ant design 的 Table 组件中提供的 onHeaderCell 方法来实现列的拖拽。具体实现方式如下: 首先,在 Table 组件的 columns 属性中,为需要支持拖拽的列添加 draggable 属性,并为每个列设置一个唯一的 key,如下所示: ``` const columns = [ { title: 'Name', dataIndex: 'name', key: 'name', draggable: true, }, { title: 'Age', dataIndex: 'age', key: 'age', draggable: true, }, { title: 'Address', dataIndex: 'address', key: 'address', draggable: true, }, ]; ``` 接下来,在 Table 组件的 onHeaderRow 方法中,为表头行添加 onMouseDown 和 onMouseMove 事件处理器,如下所示: ``` const handleMouseDown = (e, column) => { const target = e.target; target.style.cursor = 'move'; setDraggingColumn(column); }; const handleMouseMove = (e) => { const target = e.target; target.style.cursor = 'move'; }; const components = { header: { cell: (props) => ({ onMouseDown: (e) => handleMouseDown(e, props.column), onMouseMove: handleMouseMove, }), }, }; const onHeaderRow = (columns, index) => { return { columns, components, }; }; ``` 在 handleMouseDown 方法中,首先将当前拖拽的列设置为拖拽状态,然后设置鼠标样式为 move。在 handleMouseMove 方法中,设置鼠标样式为 move。 最后,在 Table 组件中添加 onHeaderCell 方法,对拖拽事件进行处理,如下所示: ``` const [draggingColumn, setDraggingColumn] = useState(null); const [dropIndex, setDropIndex] = useState(null); const onHeaderCell = (column) => { return { column, onDrop: () => { const tempColumns = [...columns]; const dragIndex = tempColumns.findIndex((c) => c.key === draggingColumn.key); const dropIndex = tempColumns.findIndex((c) => c.key === column.key); // 在 tempColumns 数组中,交换拖拽列和目标列的位置 const temp = tempColumns[dragIndex]; tempColumns[dragIndex] = tempColumns[dropIndex]; tempColumns[dropIndex] = temp; // 更新 columns 和 dropIndex 状态 setColumns(tempColumns); setDropIndex(dropIndex); }, dropClassName: dropIndex === column.index ? 'drop-over-downward' : 'drop-over-upward', // 根据拖拽列和目标列的位置,设置不同的 dropClassName }; }; <Table columns={columns.map((col) => ({ ...col, ellipsis: true, onHeaderCell: () => onHeaderCell(col), }))} dataSource={data} onHeaderRow={onHeaderRow} components={components} /> ``` 在 onHeaderCell 方法中,返回拖拽事件处理相关的属性,包括 column、onDrop 和 dropClassName。在 onDrop 方法中,首先拷贝 columns 数组,然后找到拖拽列和目标列在数组中的位置,交换它们的位置,最后更新 columns 和 dropIndex 状态。 在 Table 组件中,通过 onHeaderCell 属性来绑定 onHeaderCell 方法,实现列的拖拽。 以上就是实现 ant design table 拖拽列的方法,希望对你有所帮助!
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

范德萨_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值