ホームページ  >  記事  >  ウェブフロントエンド  >  React DNDで実装されたカードソート機能(コード例)

React DNDで実装されたカードソート機能(コード例)

不言
不言転載
2018-11-17 15:19:175709ブラウズ

この記事の内容はReact DNDで実装されているカードソート機能(コード例)ですので、お困りの方は参考にしていただければ幸いです。

私が会社で初めて React を学んだとき、要件の 1 つとしてドラッグ アンド ドロップの並べ替え機能を実装するように求められました。それが完了した後、実装方法を記録し、antd と ReactDND を使用してこの機能を実装しました。

1. 環境セットアップ

まず、create-react-app スキャフォールディングを使用して、基本的な反応プロジェクトを作成します。

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

OK、react プロジェクトがビルドされ、antdreact-dnd

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

を導入します。antd を引用した後、 antdに従うことができます 公式サイトの方法ではオンデマンド読み込みが完了します。

2. 関数の実装

まず、antd を使用して簡単なカード リストを作成し、プロジェクト ディレクトリ内の APP.js ファイルと App.css ファイルを変更して、新しいファイル 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

OK、カードの書き込みが完了しました。プロジェクトを実行して効果を確認してください

$ npm start or yarn start

React DNDで実装されたカードソート機能(コード例)

OK、書き込みは次のとおりです。ここで行う必要があるのは、react-dnd を使用してカードのドラッグ アンド ドロップの並べ替えを完了し、firstCard、secondCard、および thirdCard を自由に交換できるようにすることです。

react-dnd は、DragDropContext、DragSource、および DropTarget の 3 つの API を提供します。

  • ##DragDropContext は、ドラッグ ルート コンポーネント をラップするために使用されます。 DragSourceDropTarget は両方とも DragDropContex でラップする必要があります。

  • #DropTarget は、ドラッグをラップするために使用されます。 need コンポーネントをドラッグできるようにする移動コンポーネント

  • #DragSource

    コンポーネントを配置できるように、ドラッグ要素を受け取るコンポーネントをラップするために使用されます

  • これらの API の機能を理解すると、カード ソートを構築するアイデアが浮かび上がります。カード ソートを実装する方法は、実際には非常に簡単です。つまり、カード リスト内の各カードを次のように設定します。
DropTarget

DragSource を実行し、最後にドラッグの最後にカードの順序を変更して、この関数の実装を完了します。段階的に実装してみましょう。 最初に

DragDropContext

を設定し、App.jsreact-dndreact-dnd-html5-backend# を導入します # #(最初のnpm installこのプラグイン)

//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);
さて、App.jsでラップされたサブコンポーネントはDropTargetとDragSourceを使用できるようになりました。サブコンポーネントCardItemが表示されました。反応 dnd を設定すると、カードにドラッグ効果が与えられるようになります。
//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)
最後の接続方法については、reactDND 公式 Web サイトの手順を参照してください。lodash.flow の公式 Web サイトにアクセスして、表示してダウンロードできます。

もちろん、@DragSource(type, spec,collect) や @DropTarget(types, spec,collect) などのコンストラクター メソッドを参照用に選択することもできます。

計画していなくてもデコレータを使用する場合、__.flow などの関数合成
ヘルパーを使用して JavaScript で複数の DragSource 宣言と

DropTarget 宣言を組み合わせることができるため、部分アプリケーションは依然として便利です。デコレータを使用すると、単にスタックすることができます。

同じ効果を実現するためのデコレータ。

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);

ドラッグ効果の実装が完了したので、効果を見てみましょう

ドラッグの効果がはっきりとわかります。次に、ドラッグして配置した後で並べ替え機能を完了する必要があります。 React DNDで実装されたカードソート機能(コード例)App.js に並べ替え関数を配置し、CardItem.js の CardTarget コンストラクターの hover 関数で呼び出します。

//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>
さて、具体的な実装方法を見てみましょう。カードソート機能の小さなデモが完成しました。効果を見てみましょう!


React DNDで実装されたカードソート機能(コード例)

以上がReact DNDで実装されたカードソート機能(コード例)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はsegmentfault.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。