ホームページ > 記事 > ウェブフロントエンド > React DNDで実装されたカードソート機能(コード例)
この記事の内容はReact DNDで実装されているカードソート機能(コード例)ですので、お困りの方は参考にしていただければ幸いです。
私が会社で初めて React を学んだとき、要件の 1 つとしてドラッグ アンド ドロップの並べ替え機能を実装するように求められました。それが完了した後、実装方法を記録し、antd と ReactDND を使用してこの機能を実装しました。
まず、create-react-app
スキャフォールディングを使用して、基本的な反応プロジェクトを作成します。
npm install -g create-react-app create-react-app my-app cd my-app
OK、react プロジェクトがビルドされ、antd
と react-dnd
$ yarn add antd $ yarn add react-dnd $ yarn add react-dnd-html5-backend
を導入します。antd を引用した後、 antdに従うことができます 公式サイトの方法ではオンデマンド読み込みが完了します。
まず、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
OK、書き込みは次のとおりです。ここで行う必要があるのは、react-dnd
を使用してカードのドラッグ アンド ドロップの並べ替えを完了し、firstCard、secondCard、および thirdCard を自由に交換できるようにすることです。
react-dnd は、DragDropContext、DragSource、および DropTarget の 3 つの API を提供します。
##DragDropContext は、ドラッグ ルート コンポーネント をラップするために使用されます。 DragSource と
DropTarget は両方とも
DragDropContex でラップする必要があります。
#DropTarget は、ドラッグをラップするために使用されます。 need コンポーネントをドラッグできるようにする移動コンポーネント
コンポーネントを配置できるように、ドラッグ要素を受け取るコンポーネントをラップするために使用されます
と DragSource
を実行し、最後にドラッグの最後にカードの順序を変更して、この関数の実装を完了します。段階的に実装してみましょう。 最初に
を設定し、App.js
に react-dnd
と react-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 宣言と
同じ効果を実現するためのデコレータ。
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);
ドラッグの効果がはっきりとわかります。次に、ドラッグして配置した後で並べ替え機能を完了する必要があります。 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で実装されたカードソート機能(コード例)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。