react Dnd结合antd table实现跨表格拖拽放置和组内拖拽改变顺序功能

react Dnd结合antd table实现跨表格拖拽放置和组内拖拽改变顺序

封装通用的可拖拽表格

import React, { useState, useCallback, useRef, useEffect } from 'react';

import { DndProvider, useDrag, useDrop } from 'react-dnd';

import { HTML5Backend } from 'react-dnd-html5-backend';

import { message, Table } from 'antd';

import update from 'immutability-helper';

const ItemTypes = {
  ROW: 'row',
};

function DragTable(props) {
  const {
    dataSource,
    columns,
    onChange,
    is,
    k,
    rowSelection,
    pagination,
    ...tableProps
  } = props;

  const [list, setList] = useState([]);
  const [error, setError] = useState('');

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

  const handleDrag = useCallback(
    (col, hoverIndex) => {
      if (k !== col.record.key) {
        console.log(k, col.record.key);
        message.error('不同库不允许操作');
        return;
      }

      let dragItem = col.record;
      let newList = [];

      let flag = list.some((v, i) => {
        if (v.id === dragItem.id) {
          return true;
        } else {
          return false;
        }
      });

      if (flag) {
      //组内交换顺序
        newList = update(list, {
          $splice: [
            [col.index, 1],
            [hoverIndex, 0, dragItem],
          ],
        });
      } else {
        //跨表格拖拽
        newList = [...list];
        newList.splice(hoverIndex, 0, dragItem);
      }

      setList(newList);
      onChange(newList, dragItem, is, k, flag);
    },

    [list]
  );

  const DraggableRow = (props) => {
    const {
      index,
      record,
      handleDrag,
      rowSelection,
      pagination,
      ...restProps
    } = props;

    const ref = useRef(null);

    // 接收
    const [{ isOver, canDrop }, drop] = useDrop({
      accept: ItemTypes.ROW,

      drop: (col) => handleDrag(col, index),

      canDrop: (item) => {
        setError(undefined);
        const filter = list.filter((it) => it.id === item.id);
        if (!!filter.length) {
          setError('数据已经被放置');
          return false;
        }
        return true;
      },

      collect: (monitor) => ({
        isOver: monitor.isOver(),
        canDrop: monitor.canDrop(),
      }),
    });

    const rowStyle = { ...restProps.style };

    if (isOver && canDrop) {
      rowStyle.background = '#f0f4f8';
    }

    // 拖拽
    const [{ isDragging }, drag] = useDrag({
      // item: { type: ItemTypes.ROW, record, index },
      type: ItemTypes.ROW,
      item: () => {
        return { record, index };
      },
      collect: (monitor) => ({
        isDragging: monitor.isDragging(),
      }),
    });

    const opacity = isDragging ? 0 : 1;

    drag(drop(ref));

    return <tr ref={ref} {...restProps} style={{ ...rowStyle, opacity }}></tr>;
  };

  const components = {
    body: {
      row: DraggableRow,
    },
  };

  return (
    <DndProvider backend={HTML5Backend}>
      <Table
        className="single-table"
        {...tableProps}
        components={components}
        dataSource={list}
        columns={columns}
        onRow={(record, index) => ({
          record,
          index,
          handleDrag,
        })}
      />
    </DndProvider>
  );
}

export default DragTable;

import DragTable from './dragTable';

 handleTableDrag = (newList, dragItem, is, k, flag) => {
    let arr = deepClone(this.state.list) || [];
    let d = arr.filter((v) => v.key === k)?.[0]?.data;

    if (flag) {
      //组内交换顺序,赋新值
      d[is].libraryList = newList;
    } else {
       //跨表格拖拽
      d = d.map((v, i) => {
        v.libraryList = v.libraryList.filter((vs, is) => {
          return vs.id !== dragItem.id;
        });
        return v;
      });
      d[is].libraryList = newList;
    }
    this.setState({ list: arr });
  };
  <DragTable
     is={is}
      k={v.key}
      dataSource={dataSource}
       columns={columns}
        onChange={this.handleTableDrag}
   />
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值