本篇文章给大家带来的内容是关于React DND实现的卡片排序功能(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。
在公司初学react,其中一个要求让我实现拖拽排序的功能,完成之后记录一下实现方法,采用antd和reactDND来实现这个功能。
一、环境搭建
首先,使用 create-react-app
脚手架创建一个最基本的react项目。
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 className='card'> {CardList.map((item,index) => { return( <CardItem //向次级界面传递参数 key={item.id} title={item.title} content={item.content} index={index} /> ) })} </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 title={this.props.title} style={{ width: 300 }} > <p>{this.props.content}</p> </Card> </div> ) } } export default CardItem
好了,卡片编写完成了,现在运行一下我们的项目,看一下效果
$ npm start or yarn start
OK,编写完成,我们现在要做的就是使用react-dnd
完成卡片的拖拽排序,使得firstCard,secondCard,thirdCard可以随意的交换。
react-dnd中提供了DragDropContext,DragSource,DropTarget 3种API;
DragDropContext 用于包装拖拽根组件,
DragSource
和DropTarget
都需要包裹在DragDropContex
内DropTarget 用于包装你需要拖动的组件,使组件能够被拖拽
DragSource 用于包装接收拖拽元素的组件,使组件能够放置
理解了这些API的作用,一个卡片排序的构建思路大体就浮现出来了,怎么样实现一个卡片排序,其实很简单,就是把卡片列表中的每一个卡片都设置为DropTarget
和DragSource
,最后在拖拽结束的时候进行卡片之间的重排序,完成这一功能的实现。下面我们就来一步一步的实现它。
首先设定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);
好了,现在被App.js所包裹的子组件都可以使用DropTarget和DragSource了,我们现在在子组件CardItem中设定react-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 title={this.props.title} style={{ width: 300 ,opacity}} > <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官网 的说明,你可以去 lodash.flow的官网 进行查看并下载。
当然你也可以选择构造器的方法进行引用,如@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);
现在我们已经完成了一个拖拽效果的实现,现在我们来看一下效果
可以很明显的看到拖拽带来的效果,接下来我们要完成拖拽放置后的排序函数。
我们将排序函数放在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 } 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 //向次级界面传递参数 key={item.id} title={item.title} content={item.content} index={index} onDND={this.handleDND} />
好了,现在我们已经完成了一个卡片排序功能的小demo,让我们来看一下效果吧!
以上是React DND实现的卡片排序功能(代码示例)的详细内容。更多信息请关注PHP中文网其他相关文章!

不同JavaScript引擎在解析和执行JavaScript代码时,效果会有所不同,因为每个引擎的实现原理和优化策略各有差异。1.词法分析:将源码转换为词法单元。2.语法分析:生成抽象语法树。3.优化和编译:通过JIT编译器生成机器码。4.执行:运行机器码。V8引擎通过即时编译和隐藏类优化,SpiderMonkey使用类型推断系统,导致在相同代码上的性能表现不同。

JavaScript在现实世界中的应用包括服务器端编程、移动应用开发和物联网控制:1.通过Node.js实现服务器端编程,适用于高并发请求处理。2.通过ReactNative进行移动应用开发,支持跨平台部署。3.通过Johnny-Five库用于物联网设备控制,适用于硬件交互。

我使用您的日常技术工具构建了功能性的多租户SaaS应用程序(一个Edtech应用程序),您可以做同样的事情。 首先,什么是多租户SaaS应用程序? 多租户SaaS应用程序可让您从唱歌中为多个客户提供服务

本文展示了与许可证确保的后端的前端集成,并使用Next.js构建功能性Edtech SaaS应用程序。 前端获取用户权限以控制UI的可见性并确保API要求遵守角色库

JavaScript是现代Web开发的核心语言,因其多样性和灵活性而广泛应用。1)前端开发:通过DOM操作和现代框架(如React、Vue.js、Angular)构建动态网页和单页面应用。2)服务器端开发:Node.js利用非阻塞I/O模型处理高并发和实时应用。3)移动和桌面应用开发:通过ReactNative和Electron实现跨平台开发,提高开发效率。

JavaScript的最新趋势包括TypeScript的崛起、现代框架和库的流行以及WebAssembly的应用。未来前景涵盖更强大的类型系统、服务器端JavaScript的发展、人工智能和机器学习的扩展以及物联网和边缘计算的潜力。

JavaScript是现代Web开发的基石,它的主要功能包括事件驱动编程、动态内容生成和异步编程。1)事件驱动编程允许网页根据用户操作动态变化。2)动态内容生成使得页面内容可以根据条件调整。3)异步编程确保用户界面不被阻塞。JavaScript广泛应用于网页交互、单页面应用和服务器端开发,极大地提升了用户体验和跨平台开发的灵活性。

Python更适合数据科学和机器学习,JavaScript更适合前端和全栈开发。 1.Python以简洁语法和丰富库生态着称,适用于数据分析和Web开发。 2.JavaScript是前端开发核心,Node.js支持服务器端编程,适用于全栈开发。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

Dreamweaver Mac版
视觉化网页开发工具

MinGW - 适用于 Windows 的极简 GNU
这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

适用于 Eclipse 的 SAP NetWeaver 服务器适配器
将Eclipse与SAP NetWeaver应用服务器集成。

VSCode Windows 64位 下载
微软推出的免费、功能强大的一款IDE编辑器

PhpStorm Mac 版本
最新(2018.2.1 )专业的PHP集成开发工具