react+antd,二次封装表格拖拽组件

项目需求中,要求实现表格拖拽排序后,返回排序后数据顺序提交保存,多处使用。
曾尝试通过对Table组件的 columns 属性进行包裹,以期达到封装 DragSource 和 DropTarget 的效果,但后来发现,antd根部不会识别这样的修改。
antd官方文档提供了Table单一表格的行拖拽排序,并没有暴露出更多可详细配置的API。
在拖拽排序的案例中,BodyRow既是DragSource,也是DopTarget。那么既然如此,理应也允许针对BodyRow进行二次封装,达到DragSource与DropTarget的独立,从而实现跨表格的行(row)或列(column)的拖拽。

查阅ant Design,react相关排序,得出结论,ant Design table组件 + react-dnd结合可实现。

提供组件属性含义:

  1. 可设置“dataSource”绑定表格数据。
  2. 可设置“columns”定义表格列名。
  3. 可通过“setList获取排序后数据。
  4. 其余表格属性同ant Design相关属性设置全选、滚动、样式等一致。
// 表格拖拽排序组件
// antd-table + react-dnd
import React, { useRef } from 'react';
import { DndProvider, DragSource, DropTarget } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import update from 'immutability-helper';
import { Table } from "antd";
import { useEffect } from 'react';

let dragingIndex = -1; // 用于设置拖拽Row时样式
let moverow = null; //定义move事件,解决warn

const BodyRow = (props) => {
    const { isOver, connectDragSource, connectDropTarget, move, ...restProps } = props;
    moverow = move;
    const ref = useRef(null);
    const style = { ...restProps.style, cursor: 'move' };
    let { className } = restProps;
    if (isOver) {
        if (restProps.index > dragingIndex) {
            className += ' drop-over-downward';
        }
        if (restProps.index < dragingIndex) {
            className += ' drop-over-upward';
        }
    }
    connectDragSource(
        connectDropTarget(ref)
    );
    return <tr {...restProps} ref={ref} className={className} style={style}></tr>;
};

// DragSource 拖拽事件的方法对象
const rowSource = {
    beginDrag(props) {
        dragingIndex = props.index;
        return {
            index: props.index
        };
    }
};

// DropTarget 拖拽事件的方法对象
const rowTarget = {
    drop(props, monitor) {
        const dragIndex = monitor.getItem().index;
        const hoverIndex = props.index;
        if (dragIndex === hoverIndex) {
            return;
        }
        moverow(dragIndex, hoverIndex);
        monitor.getItem().index = hoverIndex;
    }
};

const DragableBodyRow = DropTarget('row', rowTarget, (connect, monitor) => ({
    connectDropTarget: connect.dropTarget(),
    isOver: monitor.isOver()
}))(
    DragSource('row', rowSource, connect => ({
        connectDragSource: connect.dragSource()
    }))(BodyRow)
);

/**
 * 拖拽表格
 * @param {表格数据} dataSource
 * @param {表格columns} columns
 * @param {设置数据} setList 设置数据方法
 */
function DragTable({ dataSource, columns, setList, ...tableProps }) {
    const components = {
        body: { row: DragableBodyRow }
    };
    const moveRow = (dragIndex, hoverIndex) => {
        const dragItem = dataSource[dragIndex];
        const newList = update(dataSource, {
            $splice: [
                [dragIndex, 1],
                [hoverIndex, 0, dragItem]

            ]
        });
        setList(newList);
    };

    useEffect(() => {
        setList(dataSource);
    }, [dataSource]);

    return (
        <DndProvider backend={HTML5Backend}>
            <Table
                {...tableProps}
                components={components}
                dataSource={dataSource}
                columns={columns}
                pagination={false}
                onRow={(record, index) => {
                    return { record: record, index: index, move: moveRow };
                }} />
        </DndProvider>
    );
}
export default DragTable;

使用方法:

import React, { useState, useEffect } from 'react';
import DragTable from '../component/dragTable/index.jsx'; // 引入拖拽组件

const TableDrag = () => {
    const [dataSource, setDataSource] = useState([]);
    const columns = [
        {
            title: '姓名',
            dataIndex: 'name'
        },
        {
            title: '姓别',
            dataIndex: 'sex'
        },
        {
            title: '年龄',
            dataIndex: 'age'
        },
        {
            title: '手机号',
            dataIndex: 'phone'
        }
    ];
    useEffect(() => {
        const data = [
            {
                id: 1,
                name: '张三',
                sex: '男',
                age: 10,
                phone: 12345678974
            }, {
                id: 2,
                name: '李四',
                sex: '男',
                age: 15,
                phone: 56789451234
            }, {
                id: 3,
                name: '王五',
                sex: '男',
                age: 46,
                phone: 12345678974
            }, {
                id: 4,
                name: '赵六',
                sex: '男',
                age: 60,
                phone: 12345678974
            }, {
                id: 5,
                name: '李七',
                sex: '男',
                age: 25,
                phone: 12345678974
            }
        ];
        setDataSource(data);
    }, []);
    return <div className='ui_container_box'>
        <h1>表格拖拽排序</h1>
        <b>使用ant Design 表格,结合react-dnd实现拖拽排序。</b><br />
        <span>1、可设置“<b>dataSource</b>”绑定表格数据。</span><br />
        <span>2、可设置“<b>columns</b>”定义表格列名。</span><br />
        <span>3、可通过“<b>setList</b>获取排序后数据。</span><br />
        <span>4、可设置ant design相关属性设置全选、滚动、样式等。</span><br />
        <DragTable dataSource={dataSource} columns={columns} rowKey='id' setList={setDataSource} />
    </div>;
}
export default TableDrag;
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值