Home >Web Front-end >JS Tutorial >Card sorting function implemented by React DND (code example)

Card sorting function implemented by React DND (code example)

不言
不言forward
2018-11-17 15:19:175834browse

The content of this article is about the card sorting function (code example) implemented by React DND. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.

When I first learned react in the company, one of the requirements asked me to implement the drag and drop sorting function. After completing it, I recorded the implementation method and used antd and reactDND to implement this function.

1. Environment setup

First, use create-react-app scaffolding to create a basic react project.

npm install -g create-react-app
create-react-app my-app
cd my-app

OK, the react project is built, and then we introduce antd, and react-dnd

$ yarn add antd
$ yarn add react-dnd
$ yarn add react-dnd-html5-backend

. After quoting antd, you can follow antd The method on the official website completes on-demand loading.

2. Function implementation

We first use antd to write a simple card list, modify the APP.js and App.css files in the project directory, and create a new file CardItem.js

//App.js

import React, { Component } from 'react';
import CardItem from './CardItem'
import './App.css';

const CardList = [{ //定义卡片内容
    title:"first Card",
    id:1,
    content:"this is first Card"
  },{
    title:"second Card",
    id:2,
    content:"this is second Card"
  },{
    title:"Third Card",
    id:3,
    content:"this is Third Card"
  }
];
class App extends Component {
  state = {
    CardList
  }; 
  render() {
    return (
        <div>
            {CardList.map((item,index) => {
                return(
                    <carditem></carditem>
                )
            })}
        </div>
    );
  }
}

export default App;

//App.css

.card{
  display: flex;
  margin: 50px;
}
.card div{
  margin-right: 20px;
}

//CardItem.js

import React, { Component } from 'react';
import {Card} from 'antd'

class CardItem extends Component{
    render(){
        return(
            <div>
                <card>
                    <p>{this.props.content}</p>
                </card>
            </div>
        )
    }
}

export default CardItem

Okay, the card writing is completed, now run our project and see the effect

$ npm start or yarn start

Card sorting function implemented by React DND (code example)

OK, the writing is completed, we What we need to do now is to use react-dnd to complete the drag and drop sorting of cards so that firstCard, secondCard, and thirdCard can be exchanged at will.

react-dnd provides 3 APIs: DragDropContext, DragSource, and DropTarget;

  • ##DragDropContext is used to wrap the drag root component, DragSource and DropTarget both need to be wrapped in DragDropContex

  • ##DropTarget

    is used to wrap the drag you need A moving component that enables the component to be dragged

  • DragSource

    Used to wrap components that receive drag elements so that the component can be placed

  • Understanding the function of these APIs, the idea of ​​​​constructing a card sorting has emerged. How to implement a card sorting is actually very simple, that is, setting each card in the card list to
DropTarget

and DragSource, and finally reorder the cards at the end of dragging to complete the implementation of this function. Let's implement it step by step. First set

DragDropContext

and introduce react-dnd and react-dnd-html5-backend# in App.js ##(Firstnpm installthis plug-in)

//App.js

import React, { Component } from 'react';
import CardItem from './CardItem'
+ import {DragDropContext} from 'react-dnd'
+ import HTML5Backend from 'react-dnd-html5-backend'
import './App.css';

/*..
..*/

- export default App;
+ export default DragDropContext(HTML5Backend)(App);
Okay, now the sub-components wrapped by App.js can use DropTarget and DragSource. We are now in the sub-component CardItem Setting react-dnd allows cards to now have drag effects.
//CardItem.js

import React, { Component } from 'react';
import {Card} from 'antd'
+ import { //引入react-dnd
    DragSource,
    DropTarget,
} from 'react-dnd'


const Types = { // 设定类型,只有DragSource和DropTarget的类型相同时,才能完成拖拽和放置
    CARD: 'CARD'
};

//DragSource相关设定
const CardSource = {  //设定DragSource的拖拽事件方法
    beginDrag(props,monitor,component){ //拖拽开始时触发的事件,必须,返回props相关对象
        return {
            index:props.index
        }
    },
    endDrag(props, monitor, component){
      //拖拽结束时的事件,可选
    },
    canDrag(props, monitor){
      //是否可以拖拽的事件。可选
    },
    isDragging(props, monitor){
      // 拖拽时触发的事件,可选
    }
};

function collect(connect,monitor) { //通过这个函数可以通过this.props获取这个函数所返回的所有属性
    return{
        connectDragSource:connect.dragSource(),
        isDragging:monitor.isDragging()
    }
}

//DropTarget相关设定
const CardTarget = {
    drop(props, monitor, component){ //组件放下时触发的事件
        //...
    },
    canDrop(props,monitor){ //组件可以被放置时触发的事件,可选
        //...
    },
    hover(props,monitor,component){ //组件在target上方时触发的事件,可选
        //...
    },
    
};

function collect1(connect,monitor) {//同DragSource的collect函数
    return{
        connectDropTarget:connect.dropTarget(),
        isOver:monitor.isOver(), //source是否在Target上方
        isOverCurrent: monitor.isOver({ shallow: true }), 
        canDrop: monitor.canDrop(),//能否被放置
        itemType: monitor.getItemType(),//获取拖拽组件type
    }
}
class CardItem extends Component{

    render(){
        const { isDragging, connectDragSource, connectDropTarget} = this.props;
        let opacity = isDragging ? 0.1 : 1; //当被拖拽时呈现透明效果

        return connectDragSource( //使用DragSource 和 DropTarget
            connectDropTarget( <div> 
                <card>
                    <p>{this.props.content}</p>
                </card>
            </div> )
        )
    }
}

// 使组件连接DragSource和DropTarget
let flow = require('lodash.flow');
export default flow(
    DragSource(Types.CARD,CardSource,collect),
    DropTarget(Types.CARD,CardTarget,collect1)
)(CardItem)
For the last connection method, I refer to the instructions on the reactDND official website. You can go to the official website of lodash.flow to view and download it.

Of course you can also choose the constructor method for reference, such as @DragSource(type, spec, collect) and @DropTarget(types, spec, collect).

Even if you don't plan to use decorators, the partial application can
still be handy, because you can combine several DragSource and

DropTarget declarations in JavaScript using a functional composition

helper such as _.flow. With decorators, you can just stack the
decorators to achieve the same effect.

import { DragSource, DropTarget } from 'react-dnd';
import flow from 'lodash/flow';

class YourComponent {
  render() {
    const { connectDragSource, connectDropTarget } = this.props
    return connectDragSource(connectDropTarget(
      /* ... */
    ))
  }
}

export default flow(
  DragSource(/* ... */),
  DropTarget(/* ... */)
)(YourComponent);

Now that we have completed the implementation of a drag effect, let’s take a look at the effect

Card sorting function implemented by React DND (code example)You can clearly see the effect of dragging. Next, we need to complete the sorting function after dragging and placing. We put the sorting function in App.js and call it in the hover function in the CardTarget constructor in CardItem.js. Next, let’s look at the specific implementation method.

//CardItem.js

const CardTarget = {
    hover(props,monitor,component){
        if(!component) return null; //异常处理判断
        const dragIndex = monitor.getItem().index;//拖拽目标的Index
        const hoverIndex = props.index; //放置目标Index
        if(dragIndex === hoverIndex) return null;// 如果拖拽目标和放置目标相同的话,停止执行
        
        //如果不做以下处理,则卡片移动到另一个卡片上就会进行交换,下方处理使得卡片能够在跨过中心线后进行交换.
        const hoverBoundingRect = (findDOMNode(component)).getBoundingClientRect();//获取卡片的边框矩形
        const hoverMiddleX = (hoverBoundingRect.right - hoverBoundingRect.left) / 2;//获取X轴中点
        const clientOffset = monitor.getClientOffset();//获取拖拽目标偏移量
        const hoverClientX = (clientOffset).x - hoverBoundingRect.left;
        if (dragIndex  hoverIndex && hoverClientX > hoverMiddleX) { // 从后往前放置
            return null
        }
        props.DND(dragIndex,hoverIndex); //调用App.js中方法完成交换
        monitor.getItem().index = hoverIndex; //重新赋值index,否则会出现无限交换情况
    }
}
//App.js

    handleDND = (dragIndex,hoverIndex) => {
        let CardList = this.state.CardList;
        let tmp = CardList[dragIndex] //临时储存文件
        CardList.splice(dragIndex,1) //移除拖拽项
        CardList.splice(hoverIndex,0,tmp) //插入放置项
        this.setState({
            CardList
        })
    };
    
    
    /* ...
           */
           
    //添加传递参数传递函数
    <carditem></carditem>

Okay, now We have completed a small demo of the card sorting function, let's take a look at the effect!

Card sorting function implemented by React DND (code example)

The above is the detailed content of Card sorting function implemented by React DND (code example). For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:segmentfault.com. If there is any infringement, please contact admin@php.cn delete