自己随手写了一个小案例,记录一下。

1、实现右边盒子内容拖到左边盒子里。

依赖 -- -- 

react-dnd 
react-dnd-html5-backend
 
2、实现左边盒子资源的拖动
依赖 -- -- 
react-beautiful-dnd
 
(1) ---- index.js
import React, { Component } from "react";
import { DndProvider } from 'react-dnd'
import { HTML5Backend } from 'react-dnd-html5-backend'
import Dustbin from "./Dustbin";
import Box from "./Box";
import "./index.less";

class Home extends Component {
  state = {
    mainList: [
      {id: 'item-6', content: 'aaaaaaaaa'},
      {id: 'item-7', content: 'bbbbbbbbb'},
      {id: 'item-8', content: 'ccccccccc'},
      {id: 'item-9', content: 'ddddddddd'},
      {id: 'item-10', content: 'eeeeeeeee'},
      {id: 'item-11', content: 'fffffffff'},
    ],
    sideList: [
      { id: "item-0", content: "hello" },
      { id: "item-1", content: "I" },
      { id: "item-2", content: "am" },
      { id: "item-3", content: "卡" },
      { id: "item-4", content: "特" },
      { id: "item-5", content: "洛" },
    ]
  }

  endPull = (opt) => {
    const sideList = [...this.state.sideList, opt];
    // alert('添加成功')
    this.setState({ sideList })
  }

  reOrder = (list, startIndex, endIndex) => {
    const result = Array.from(list);
    const [removed] = result.splice(startIndex, 1);
    result.splice(endIndex, 0, removed);
    return result;
  };

  onDragEnd = (result) => {
    console.log(result)
    if (!result.destination) return;

    const sideList = this.reOrder(
      this.state.sideList,
      result.source.index,
      result.destination.index
    );
    this.setState({ sideList })
  };

  render() {
    return (
      <div style={{ paddingLeft: 200, paddingTop: 50, display: 'flex' }} className='page-home'>
       <DndProvider backend={HTML5Backend}>
        <div>
          <Dustbin sideList={this.state.sideList} switchSeat= {sideList => this.setState({ sideList })} />
        </div>

        <div style={{flex: 1, display: 'flex', flexWrap: 'wrap'}}>
          {/* 案例实现的是循环里数据都能实现拖拽,所以要循环组件 */}
          {
            this.state.mainList.map(item => {
              return (
                <Box
                  key={item.id} 
                  item={item}
                  endPull={this.endPull}
                />
              )
            })
          }
        </div>
       </DndProvider>
      </div>
    );
  }
}

export default Home

  

(2) -- -- Box.index

import React from "react";
import { DragSource } from "react-dnd";
let endPull = null;

const boxSource = {
  /**
   * 开始拖拽时触发当前函数
   * @param {*} props 组件的 props
   */
  beginDrag(props) {
    // 返回的对象可以在 monitor.getItem() 中获取到
    return {
      // name: props.name,
    };
  },

  /**
   * 拖拽结束时触发当前函数
   * @param {*} props 当前组件的 props
   * @param {*} monitor DragSourceMonitor 对象
   */
  endDrag(props, monitor) {
    // 当前拖拽的 item 组件
    // const item = monitor.getItem();
    // 拖拽元素放下时,drop 结果
    const dropResult = monitor.getDropResult();
    // 如果 drop 结果存在,就弹出 alert 提示
    if (dropResult) {
      // alert(`You dropped ${item.name} into ${dropResult.name}!`);
      if(!endPull) return;
      endPull(props.item);
    }
  },
};

@DragSource(
  // type 标识,这里是字符串 'box'
  // ItemTypes.BOX,
  'box',
  // 拖拽事件对象
  boxSource,
  // 收集功能函数,包含 connect 和 monitor 参数
  // connect 里面的函数用来将 DOM 节点与 react-dnd 的 backend 建立联系
  (connect, monitor) => ({
    // 包裹住 DOM 节点,使其可以进行拖拽操作
    connectDragSource: connect.dragSource(),
    // 是否处于拖拽状态
    isDragging: monitor.isDragging(),
  })
)

class Box extends React.Component {
  componentDidMount() {
    endPull = this.props.endPull;
  }

  render() {
    const { connectDragSource } = this.props;
    const { item } = this.props;
    // 使用 connectDragSource 包裹住 DOM 节点,使其可以接受各种拖动 API, connectDragSource 包裹住的 DOM 节点才可以被拖动

    return (
      <div style={{display: 'flex'}}>
        {
          connectDragSource &&
          connectDragSource(
            <div key={item.key} style={{width: '200px', margin: '50px'}}>
              <dl style={{width: '200px', height: '100px'}}>
                <dt style={{height: '70px', background: 'pink'}}>图片</dt>
                <dd style={{height: '30px', background: '#eee'}}>{item.content}</dd>
              </dl>
            </div>
          )
        }
      </div>
    );
  }
}

export default Box;

  

(3) -- -- Dustbin.js

import React from "react";
import { DropTarget } from "react-dnd";
import { Collapse } from "antd";
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";

const { Panel } = Collapse;

const boxTarget = {
  // 当有对应的 drag source 放在当前组件区域时,会返回一个对象,可以在 monitor.getDropResult() 中获取到
  drop: () => ({ name: "Dustbin" }),
};

@DropTarget(
  // type 标识,这里是字符串 'box'
  // ItemTypes.BOX,
  "box",
  // 接收拖拽的事件对象
  boxTarget,
  // 收集功能函数,包含 connect 和 monitor 参数
  // connect 里面的函数用来将 DOM 节点与 react-dnd 的 backend 建立联系
  (connect, monitor) => ({
    // 包裹住 DOM 节点,使其可以接收对应的拖拽组件
    connectDropTarget: connect.dropTarget(),
    // drag source是否在 drop target 区域
    isOver: monitor.isOver(),
    // 是否可以被放置
    canDrop: monitor.canDrop(),
  })
)
class Dustbin extends React.Component {
  state = {
    keyActive: "1",
    periodList: [
      { id: 1, name: "测试1" },
      { id: 2, name: "测试2" },
      { id: 3, name: "测试3" },
    ],
  };

  onCollapseChange = (key) => {
    if (key) {
      this.setState({ keyActive: key });
    }
  };

  reOrder = (list, startIndex, endIndex) => {
    const result = Array.from(list);
    const [removed] = result.splice(startIndex, 1);
    result.splice(endIndex, 0, removed);
    return result;
  };

  onDragEnd = (result) => {
    console.log(result);
    if (!result.destination) return;

    const sideList = this.reOrder(
      this.props.sideList,
      result.source.index,
      result.destination.index
    );

    this.props.switchSeat(sideList);
  };

  render() {
    const { connectDropTarget } = this.props;
    const { sideList } = this.props;
    const { keyActive, periodList } = this.state;

    return (
      <div
        style={{ width: "200px", border: "1px solid gray", height: "500px" }}
      >
        <Collapse
          accordion
          ghost
          className="collapse_wrap"
          // activeKey={1}
          activeKey={keyActive}
          onChange={this.onCollapseChange}
        >
          {periodList &&
            periodList.map((item, index) => {
              return (
                <Panel header={item.name} key={item.id} showArrow={false}>
                  <React.Fragment>
                    {connectDropTarget &&
                      connectDropTarget(
                        <div>
                          <DragDropContext
                            onDragEnd={this.onDragEnd}
                          >
                            <Droppable droppableId="droppable">
                              {(provided) => (
                                <div
                                  ref={provided.innerRef}
                                  {...provided.droppableProps}
                                >
                                  {sideList.map((item, index) => (
                                    <Draggable
                                      // 这个key值必须是string类型, 不能是number, 想知道为什么,自己试下就知道了。
                                      key={item.id}
                                      draggableId={item.id}
                                      index={index}
                                    >
                                      {(provided) => (
                                        <div
                                          ref={provided.innerRef}
                                          {...provided.draggableProps}
                                          {...provided.dragHandleProps}
                                        >
                                          <span
                                            style={{
                                              display: "block",
                                              height: "30px",
                                              lineHeight: "30px",
                                              borderBottom: "1px solid red",
                                              paddingLeft: "10px",
                                            }}
                                          >
                                            {item.content}
                                          </span>
                                        </div>
                                      )}
                                    </Draggable>
                                  ))}
                                  {provided.placeholder}
                                </div>
                              )}
                            </Droppable>
                          </DragDropContext>
                        </div>
                      )}
                  </React.Fragment>

                  {/* {
                    connectDropTarget &&
                    connectDropTarget(
                      <div className='class_hour_list'>
                        {
                          detailList.map(v => {
                            return (
                              <p key={v}>{v.name}</p>
                            )
                          })
                        }
                      </div>
                    )
                  } */}
                </Panel>
              );
            })}
        </Collapse>
      </div>
    );
  }
}

export default Dustbin;

  

posted on 2021-05-25 10:28  姓叶,名铁柱  阅读(306)  评论(0编辑  收藏  举报