使用react-dnd实现跨表格的行拖拽

功能点:
1.表格内的行拖拽(drag和drop都放在行上)
2.跨表格的行拖拽(drag事件都放在行上,表格不空时drop事件放在行上,表格空时drop事件放在空提示上)
3.表格拖拽(drag和drop都放在表格的header上)

MytableV3.js

import React from "react";
import { Table, ConfigProvider, Icon } from "antd";
import { DndProvider, DragSource, DropTarget } from "react-dnd";
import { HTML5Backend } from "react-dnd-html5-backend";
import update from "immutability-helper";
import uuid from "uuid";

let dragingIndex = -1;

class BodyRow extends React.Component {
  render() {
    const {
      isOver,
      connectDragSource,
      connectDropTarget,
      moveRow,
      delRow,
      ...restProps
    } = this.props;
    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";
      }
    }

    return connectDragSource(
      connectDropTarget(
        <tr {...restProps} className={className} style={style} />
      )
    );
  }
}

class HeaderRow extends React.Component {
  render() {
    const {
      isOver,
      connectDragSource,
      connectDropTarget,
      moveRow,
      delRow,
      ...restProps
    } = this.props;
    const style = { ...restProps.style, cursor: "move" };

    return connectDragSource(
      connectDropTarget(<tr {...restProps} style={style} />)
    );
  }
}

class EmptyBody extends React.Component {
  render() {
    const { isOver, connectDragSource, connectDropTarget, ...restProps } =
      this.props;
    return connectDragSource(
      connectDropTarget(
        <div style={{ textAlign: "center" }}>
          <Icon type="smile" style={{ fontSize: 20 }} />
          <p>空状态信息提示</p>
        </div>
      )
    );
  }
}

const rowSource = {
  beginDrag(props) {
    // debugger;
    dragingIndex = props.index;
    return {
      index: props.index,
      record: props.record,
      tablekey: props.tablekey,
    };
  },
  endDrag(props, monitor) {
    // DragSourceMonitor
    // monitor.canDrag(); // 是否能被拖拽
    // monitor.isDragging(); // 是否正在拖拽
    // monitor.getItemType(); // 拖拽组件type
    // monitor.getItem(); // 当前拖拽的item
    // monitor.getDropResult(); // 查询drop结果
    // monitor.didDrop(); // source是否已经drop在target
    // monitor.getInitialClientOffset(); // 拖拽组件初始拖拽时offset
    // monitor.getInitialSourceClientOffset();
    // monitor.getClientOffset(); // 拖拽组件当前offset
    // monitor.getDifferenceFromInitialOffset(); // 当前拖拽offset和初始拖拽offset的差别
    // monitor.getSourceClientOffset();
    const dragKey = props.tablekey;
    const hoverKey = monitor.getItem().tablekey;
    const dragIndex = props.index;
    // const hoverIndex = monitor.getItem().index;
    // const dragRecord = props.record;
    // const hoverRecord = monitor.getItem().record;
    if (dragKey !== hoverKey) {
      props.delRow(dragIndex);
    }
  },
};

const rowTarget = {
  drop(props, monitor) {
    // DropTargetMonitor
    // monitor.canDrop()         // 是否可被放置
    // monitor.isOver(options)   // source是否在target上方
    // monitor.getItemType()     // 拖拽组件type
    // monitor.getItem()         // 当前拖拽的item
    // monitor.getDropResult()   // 查询drop结果
    // monitor.didDrop()         // source是否已经drop在target
    // monitor.getInitialClientOffset()   // 拖拽组件初始拖拽时offset
    // monitor.getInitialSourceClientOffset()
    // monitor.getClientOffset() // 拖拽组件当前offset
    // monitor.getDifferenceFromInitialOffset() // 当前拖拽offset和初始拖拽offset的差别
    // monitor.getSourceClientOffset()
    // debugger
    const dragKey = monitor.getItem().tablekey;
    const hoverKey = props.tablekey;
    const dragIndex = monitor.getItem().index;
    const hoverIndex = props.index;
    const dragRecord = monitor.getItem().record;
    const hoverRecord = props.record;

    // Don't replace items with themselves
    if (dragIndex === hoverIndex && dragKey === hoverKey) {
      return;
    }

    // Time to actually perform the action
    props.moveRow(
      dragIndex,
      hoverIndex,
      dragKey,
      hoverKey,
      dragRecord,
      hoverRecord
    );

    // Note: we're mutating the monitor item here!
    // Generally it's better to avoid mutations,
    // but it's good here for the sake of performance
    // to avoid expensive index searches.
    monitor.getItem().index = hoverIndex;
    monitor.getItem().record = props.record;
    monitor.getItem().tablekey = props.tablekey;
  },
};

const myTarget = {
  drop(props, monitor) {
    const { record } = monitor.getItem();
    props.inRow(record);
    monitor.getItem().index = props.index;
    monitor.getItem().record = props.record;
    monitor.getItem().tablekey = props.tablekey;
  },
};

const headerTarget = {
  drop(props, monitor) {
    const dragKey = monitor.getItem().tablekey
    const dropKey = props.tablekey
    props.moveTable(dragKey,dropKey);
  },
};
const headerSource = {
  beginDrag(props, monitor) {
    return {
      tablekey: props.tablekey,
    };
  },
};

const DragableBodyRow = DropTarget("row", rowTarget, (connect, monitor) => ({
  connectDropTarget: connect.dropTarget(),
  isOver: monitor.isOver(),
}))(
  DragSource("row", rowSource, (connect) => ({
    connectDragSource: connect.dragSource(),
  }))(BodyRow)
);
const DragableHeaderRow = DropTarget(
  "header",
  headerTarget,
  (connect, monitor) => ({
    connectDropTarget: connect.dropTarget(),
    isOver: monitor.isOver(),
  })
)(
  DragSource("header", headerSource, (connect) => ({
    connectDragSource: connect.dragSource(),
  }))(HeaderRow)
);

const EmptyBodyC = DropTarget("row", myTarget, (connect, monitor) => ({
  connectDropTarget: connect.dropTarget(),
  isOver: monitor.isOver(),
}))(
  DragSource("row", rowSource, (connect) => ({
    connectDragSource: connect.dragSource(),
  }))(EmptyBody)
);

const columns = [
  {
    title: "Name",
    dataIndex: "name",
    key: "name",
  },
  {
    title: "Age",
    dataIndex: "age",
    key: "age",
  },
  {
    title: "Address",
    dataIndex: "address",
    key: "address",
  },
];

const datas1 = [
  {
    key: uuid(),
    name: "John Brown",
    age: 32,
    address: "New York No. 1 Lake Park",
  },
  {
    key: uuid(),
    name: "Jim Green",
    age: 42,
    address: "London No. 1 Lake Park",
  },
  {
    key: uuid(),
    name: "Joe Black",
    age: 32,
    address: "Sidney No. 1 Lake Park",
  },
];
const datas2 = [
  {
    key: uuid(),
    name: "张三",
    age: 32,
    address: "New York No. 1 Lake Park",
  },
  {
    key: uuid(),
    name: "李四",
    age: 42,
    address: "London No. 1 Lake Park",
  },
  {
    key: uuid(),
    name: "王五",
    age: 32,
    address: "Sidney No. 1 Lake Park",
  },
];

class DragSortingTable extends React.Component {
  state = {
    data: this.props.tablekey === "111" ? datas1 : datas2,
  };

  components = {
    header: {
      row: DragableHeaderRow,
    },
    body: {
      row: DragableBodyRow,
    },
  };

  moveRow = (
    dragIndex,
    hoverIndex,
    dragKey,
    hoverKey,
    dragRecord,
    hoverRecord
  ) => {
    const { data } = this.state;

    if (dragKey === hoverKey) {
      const dragRow = data[dragIndex];
      this.setState(
        update(this.state, {
          data: {
            $splice: [
              [dragIndex, 1],
              [hoverIndex, 0, dragRow],
            ],
          },
        })
      );
    } else {
      this.setState(
        update(this.state, {
          data: {
            $splice: [[hoverIndex + 1, 0, dragRecord]],
          },
        })
      );
    }
  };

  delRow = (dragIndex) => {
    // const { data } = this.state;
    // const dragRow = data[dragIndex];
    this.setState(
      update(this.state, {
        data: {
          $splice: [[dragIndex, 1]],
        },
      })
    );
  };

  inRow = (record) => {
    this.setState(
      update(this.state, {
        data: {
          $push: [record],
        },
      })
    );
  };

  moveTable = (dragKey,dropKey)=>{
    this.props.changeIndex(dragKey,dropKey)
  }

  render() {
    const data = this.props.tablekey === "111" ? datas1 : datas2
    if (this.state.data.length) {
      return (
        <DndProvider backend={HTML5Backend}>
          <Table
            columns={columns}
            // dataSource={this.state.data}
            dataSource={data}
            components={this.components}
            onRow={(record, index) => ({
              index,
              record: record,
              moveRow: this.moveRow,
              delRow: this.delRow,
              tablekey: this.props.tablekey,
            })}
            onHeaderRow={(record, index) => ({
              index,
              record,
              moveTable: this.moveTable,
              tablekey: this.props.tablekey,
            })}
          />
        </DndProvider>
      );
    } else {
      // const customizeRenderEmpty = () => (
      //   //这里面就是我们自己定义的空状态
      //   <div style={{ textAlign: "center" }}>
      //     <Icon type="smile" style={{ fontSize: 20 }} />
      //     <p>空状态信息提示</p>
      //   </div>
      // );
      const customizeRenderEmpty = () => (
        //这里面就是我们自己定义的空状态
        <EmptyBodyC inRow={this.inRow} delRow={this.delRow} />
      );
      return (
        <DndProvider backend={HTML5Backend}>
          <ConfigProvider renderEmpty={customizeRenderEmpty}>
            <Table columns={columns} dataSource={this.state.data} />
          </ConfigProvider>
        </DndProvider>
      );
    }
  }
}
export default DragSortingTable;

Drag.js

import "antd/dist/antd.css";
import React, { Component } from "react";
import DragSortingTable from "./components/MytableV3";

class Drag extends Component {
  constructor(props) {
    super(props);
    this.state = {
      keys: ["111", "222"],
    };
  }

  changeIndexH = (dragKey, dropKey) => {
    const dragIndex = this.state.keys.findIndex((item) => item === dragKey);
    const dropIndex = this.state.keys.findIndex((item) => item === dropKey);
    const keys = [...this.state.keys];
    keys.splice(dragIndex, 1);
    keys.splice(dropIndex, 0, this.state.keys[dragIndex]);
    this.setState({
      keys,
    });
  };

  render() {
    const $LIST = this.state.keys.map((item) => {
      return (
        <DragSortingTable
          tablekey={item}
          changeIndex={(dragKey, dropKey) => {
            this.changeIndexH(dragKey, dropKey);
          }}
        />
      );
    });

    return (
        <div>{$LIST}</div>
    );
  }
}

export default Drag;

上一篇:297. 二叉树的序列化与反序列化


下一篇:上手 WebRTC DTLS 遇到很多 BUG?浅谈 DTLS Fragment