摘要:簡介在公司初學(xué)其中一個要求讓我實(shí)現(xiàn)拖拽排序的功能完成之后記錄一下實(shí)現(xiàn)方法,采用和來實(shí)現(xiàn)這個功能。一環(huán)境搭建首先,使用腳手架創(chuàng)建一個最基本的項(xiàng)目。
簡介
在公司初學(xué)react,其中一個要求讓我實(shí)現(xiàn)拖拽排序的功能,完成之后記錄一下實(shí)現(xiàn)方法,采用antd和reactDND來實(shí)現(xiàn)這個功能。
一、環(huán)境搭建首先,使用 create-react-app 腳手架創(chuàng)建一個最基本的react項(xiàng)目。
npm install -g create-react-app create-react-app my-app cd my-app
OK,構(gòu)建好了react項(xiàng)目,然后我們引入antd,和react-dnd
$ yarn add antd $ yarn add react-dnd $ yarn add react-dnd-html5-backend
引用完antd后可以按照antd官網(wǎng)上的方法完成按需加載。
二、功能實(shí)現(xiàn)我們先使用antd寫出一個簡單的卡片列表,修改項(xiàng)目目錄的APP.js和App.css文件,新建一個文件CardItem.js
//App.js import React, { Component } from "react"; import CardItem from "./CardItem" import "./App.css"; const CardList = [{ //定義卡片內(nèi)容 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 ({CardList.map((item,index) => { return(); } } 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() })} ) } } export default CardItem{this.props.content}
好了,卡片編寫完成了,現(xiàn)在運(yùn)行一下我們的項(xiàng)目,看一下效果
$ npm start or yarn start
OK,編寫完成,我們現(xiàn)在要做的就是使用react-dnd完成卡片的拖拽排序,使得firstCard,secondCard,thirdCard可以隨意的交換。
react-dnd中提供了DragDropContext,DragSource,DropTarget 3種API;
DragDropContext 用于包裝拖拽根組件,DragSource 和 DropTarget 都需要包裹在DragDropContex內(nèi)
DropTarget 用于包裝你需要拖動的組件,使組件能夠被拖拽
DragSource 用于包裝接收拖拽元素的組件,使組件能夠放置
理解了這些API的作用,一個卡片排序的構(gòu)建思路大體就浮現(xiàn)出來了,怎么樣實(shí)現(xiàn)一個卡片排序,其實(shí)很簡單,就是把卡片列表中的每一個卡片都設(shè)置為DropTarget和DragSource,最后在拖拽結(jié)束的時候進(jìn)行卡片之間的重排序,完成這一功能的實(shí)現(xiàn)。下面我們就來一步一步的實(shí)現(xiàn)它。
首先設(shè)定DragDropContext,在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);
好了,現(xiàn)在被App.js所包裹的子組件都可以使用DropTarget和DragSource了,我們現(xiàn)在在子組件CardItem中設(shè)定react-dnd使得卡片現(xiàn)在能夠有拖動的效果。
//CardItem.js import React, { Component } from "react"; import {Card} from "antd" + import { //引入react-dnd DragSource, DropTarget, } from "react-dnd" const Types = { // 設(shè)定類型,只有DragSource和DropTarget的類型相同時,才能完成拖拽和放置 CARD: "CARD" }; //DragSource相關(guān)設(shè)定 const CardSource = { //設(shè)定DragSource的拖拽事件方法 beginDrag(props,monitor,component){ //拖拽開始時觸發(fā)的事件,必須,返回props相關(guān)對象 return { index:props.index } }, endDrag(props, monitor, component){ //拖拽結(jié)束時的事件,可選 }, canDrag(props, monitor){ //是否可以拖拽的事件??蛇x }, isDragging(props, monitor){ // 拖拽時觸發(fā)的事件,可選 } }; function collect(connect,monitor) { //通過這個函數(shù)可以通過this.props獲取這個函數(shù)所返回的所有屬性 return{ connectDragSource:connect.dragSource(), isDragging:monitor.isDragging() } } //DropTarget相關(guān)設(shè)定 const CardTarget = { drop(props, monitor, component){ //組件放下時觸發(fā)的事件 //... }, canDrop(props,monitor){ //組件可以被放置時觸發(fā)的事件,可選 //... }, hover(props,monitor,component){ //組件在target上方時觸發(fā)的事件,可選 //... }, }; function collect1(connect,monitor) {//同DragSource的collect函數(shù) 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; //當(dāng)被拖拽時呈現(xiàn)透明效果 return connectDragSource( //使用DragSource 和 DropTarget connectDropTarget() ) } } // 使組件連接DragSource和DropTarget let flow = require("lodash.flow"); export default flow( DragSource(Types.CARD,CardSource,collect), DropTarget(Types.CARD,CardTarget,collect1) )(CardItem){this.props.content}
最后這個連接方法我參考了 reactDND官網(wǎng) 的說明,你可以去 lodash.flow的官網(wǎng) 進(jìn)行查看并下載。
當(dāng)然你也可以選擇構(gòu)造器的方法進(jìn)行引用,如@DragSource(type, spec, collect)和@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);
現(xiàn)在我們已經(jīng)完成了一個拖拽效果的實(shí)現(xiàn),現(xiàn)在我們來看一下效果
可以很明顯的看到拖拽帶來的效果,接下來我們要完成拖拽放置后的排序函數(shù)。
我們將排序函數(shù)放在App.js當(dāng)中,在CardItem.js中的CardTarget構(gòu)造方法中的hover函數(shù)中進(jìn)行調(diào)用,接下來看具體的實(shí)現(xiàn)方法.
//CardItem.js const CardTarget = { hover(props,monitor,component){ if(!component) return null; //異常處理判斷 const dragIndex = monitor.getItem().index;//拖拽目標(biāo)的Index const hoverIndex = props.index; //放置目標(biāo)Index if(dragIndex === hoverIndex) return null;// 如果拖拽目標(biāo)和放置目標(biāo)相同的話,停止執(zhí)行 //如果不做以下處理,則卡片移動到另一個卡片上就會進(jìn)行交換,下方處理使得卡片能夠在跨過中心線后進(jìn)行交換. const hoverBoundingRect = (findDOMNode(component)).getBoundingClientRect();//獲取卡片的邊框矩形 const hoverMiddleX = (hoverBoundingRect.right - hoverBoundingRect.left) / 2;//獲取X軸中點(diǎn) const clientOffset = monitor.getClientOffset();//獲取拖拽目標(biāo)偏移量 const hoverClientX = (clientOffset).x - hoverBoundingRect.left; if (dragIndex < hoverIndex && hoverClientX < hoverMiddleX) { // 從前往后放置 return null } if (dragIndex > hoverIndex && hoverClientX > hoverMiddleX) { // 從后往前放置 return null } props.DND(dragIndex,hoverIndex); //調(diào)用App.js中方法完成交換 monitor.getItem().index = hoverIndex; //重新賦值index,否則會出現(xiàn)無限交換情況 } }
//App.js handleDND = (dragIndex,hoverIndex) => { let CardList = this.state.CardList; let tmp = CardList[dragIndex] //臨時儲存文件 CardList.splice(dragIndex,1) //移除拖拽項(xiàng) CardList.splice(hoverIndex,0,tmp) //插入放置項(xiàng) this.setState({ CardList }) }; /* ... */ //添加傳遞參數(shù)傳遞函數(shù)
好了,現(xiàn)在我們已經(jīng)完成了一個卡片排序功能的小demo,讓我們來看一下效果吧!
END本人初學(xué)前端不久,剛接觸react相關(guān),這篇文章也是用于記錄一下自己工作時用到的一些小功能,本文參考了
強(qiáng)大的拖拽組件:React DnD 的使用
和 reactDND 官網(wǎng)上的相關(guān)例子,一些更復(fù)雜的情況大家也可以去reactDND的官網(wǎng)上查看.
源代碼地址:https://github.com/wzb0709/Ca...
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/108662.html
摘要:注意點(diǎn)在鼠標(biāo)操作拖放期間,有一些事件可能觸發(fā)多次,比如和??赏献г?,建議使用,設(shè)定可拖拽元素的鼠標(biāo)游標(biāo),提升交互。在中使用拖拽中使用可以直接綁定到組件上。 什么是 Drag and Drop (拖放)? 簡單來說,HTML5 提供了 Drag and Drop API,允許用戶用鼠標(biāo)選中一個可拖動元素,移動鼠標(biāo)拖放到一個可放置到元素的過程。 我相信每個人都或多或少接觸過拖放,比如瀏覽...
摘要:在初步完成了在線流程圖編輯工具之后又接到了在線搭建頁面工具的需求剛開始其實(shí)并不想接項(xiàng)目因?yàn)閺臍v史以及現(xiàn)實(shí)原因來看個性化及動態(tài)渲染都是很難解決的痛點(diǎn)各種頁面搭建工具的不溫不火早已說明了這條路并沒有這么好走但從另一個方面來說既然有了這樣的需求那 在初步完成了在線流程圖編輯工具之后,又接到了在線搭建頁面工具的需求,剛開始其實(shí)并不想接項(xiàng)目,因?yàn)閺臍v史以及現(xiàn)實(shí)原因來看,個性化及動態(tài)渲染都是很難解決的痛...
摘要:啟動項(xiàng)目教程最終的目的是構(gòu)建一個帶有趣的應(yīng)用程序來自,可以在視口周圍拖動。創(chuàng)建組件,添加樣式和數(shù)據(jù)為簡單起見,我們將在文件中編寫所有樣式??梢钥闯?,就是在當(dāng)前的外層包裹我們所需要實(shí)現(xiàn)的功能?,F(xiàn)在已經(jīng)知道如何在項(xiàng)目中實(shí)現(xiàn)拖放 翻譯:https://css-tricks.com/draggi... React 社區(qū)提供了許多的庫來實(shí)現(xiàn)拖放的功能,例如 react-dnd, react-b...
摘要:最近的項(xiàng)目里需要實(shí)現(xiàn)一個標(biāo)簽組件,內(nèi)部標(biāo)簽可任意拖動排序。網(wǎng)上搜了一圈發(fā)現(xiàn)幾乎沒有現(xiàn)成的基于的組件能很好的滿足需求。 最近的項(xiàng)目里需要實(shí)現(xiàn)一個標(biāo)簽組件,內(nèi)部標(biāo)簽可任意拖動排序。網(wǎng)上搜了一圈發(fā)現(xiàn)幾乎沒有現(xiàn)成的基于react的組件能很好的滿足需求。 較為知名的是react-dnd,然而它似乎只支持把一個元素移到固定的位置,我需要的是一個標(biāo)簽可以移動到任意位置的兩個標(biāo)簽之間(每個標(biāo)簽長度不固...
摘要:不多說,直接上代碼需要版本貌似與方法有關(guān)類似的高階組件包裹被拖的元素高階組件包裹被釋放的元素這個庫是必須的,類似于的合成事件解決瀏覽器差異,抽象事件操作為可以處理的 不多說,直接上代碼 react-dnd 需要react版本 > 16.6 ,貌似與react.memo方法有關(guān) import React from react // DragDropContext 類似React的Co...
閱讀 2340·2023-04-25 14:17
閱讀 1532·2021-11-23 10:02
閱讀 2177·2021-11-23 09:51
閱讀 890·2021-10-14 09:49
閱讀 3392·2021-10-11 10:57
閱讀 2930·2021-09-24 09:47
閱讀 3058·2021-08-24 10:00
閱讀 2307·2019-08-29 18:46