自己随手写了一个小案例,记录一下。
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={{ '200px', margin: '50px'}}> <dl style={{ '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={{ "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;