react项目中使用react-dnd实现列表的拖拽排序

2023-11-18

现在有一个新需求就是需要对一个列表,实现拖拽排序的功能,要实现的效果如下图:

 

可以通过 react-dnd 或者 react-beautiful-dnd 两种方式实现,今天先讲下使用react-dnd是如何实现的,github地址:

https://react-dnd.github.io/react-dnd/docs/api/dnd-provider

1.先安装依赖

npm i react-dnd

npm i react-dnd-html5-backend

2.创建一个 index.js 文件

DndProvider 组件为您的应用程序提供 React-DnD 功能。这必须通过 backend 支柱注入后端,但也可以注入 window 物体。

  • backend:必填。一个React DnD后端。除非您正在编写自定义的,否则您可能希望使用React DnD附带的HTML5后端。
  • context: 可选的。用于配置后端的后端上下文。这取决于后端实现。
  • options: 可选的。用于配置后端的选项对象。这取决于后端实现。
import React from 'react'
import Example from './example'
import { DndProvider } from 'react-dnd'
import HTML5Backend from 'react-dnd-html5-backend'
	
class App extends React.Component{
    
    /**
    * 获取排序后的新数据回调函数
    */
    handlePreviewList = (previewList) => {
        this.setState({
             previewList
        })
    }
	return (
		<div className="App">
			<DndProvider backend={HTML5Backend}>
				<Example previewList={previewList} 
                    handlePreviewList={this.handlePreviewList}/>
			</DndProvider>
		</div>
	)
}
	
export default App;

3.新建example.js文件

previewList是 index.js组件传入的数据。

handlePreviewList 是保存排序后的新数据。

import React, { useState } from 'react'
import TopicList from './TopicList';

const Container = ({ previewList, handlePreviewList }) => {
    {
        const [topic] = useState(previewList)
        const handleDND = (dragIndex, hoverIndex) => {
            let tmp = previewList[dragIndex] //临时储存文件
            previewList.splice(dragIndex, 1) //移除拖拽项
            previewList.splice(hoverIndex, 0, tmp) //插入放置项
            handlePreviewList(previewList)
        };
        const renderCard = (item, index) => {
            return (
                <TopicList
                    key={item.questionTuid}
                    index={index}
                    id={item.questionTuid}
                    text={item.questionContent}
                    moveCard={handleDND}
                />
            )
        }
        return (
            <div>
                {
                    topic.map((item, i) => renderCard(item, i))
                }
            </div>
        )
    }
}
export default Container

4.新建TopicLis.js文件

useDrag 一个钩子,用于将当前组件用作拖动源。

参数

  • spec规范对象

返回值数组

  • Index 0:包含collect函数中收集的属性的对象。如果collect未定义任何函数,则返回空对象。
  • Index 1:拖动源的连接器功能。这必须附加到DOM的可拖动部分。
  • Index 2:拖动预览的连接器功能。这可以附加到DOM的预览部分。

规范对象成员

  • item:必填。一个简单的JavaScript对象,描述被拖动的数据。这是关于拖动源的放置目标可用的唯一信息,因此选择他们需要知道的最小数据非常重要。你可能想在这里放一个复杂的引用,但是你应该尽量避免这样做,因为它耦合了拖动源和放下目标。返回类似于{ type, id }此方法的东西是个好主意。

    item.type必须设置,它必须是字符串,ES6符号。只有为相同类型注册的放置目标才会对此项目做出反应。阅读概述以了解有关项目和类型的更多信息。

  • previewOptions: 可选的。描述拖动预览选项的纯JavaScript对象。

  • options: 可选的。一个普通的对象。如果组件的某些道具不是标量(即,不是原始值或函数),则arePropsEqual(props, otherProps)options对象内指定自定义函数可以提高性能。除非您遇到性能问题,否则不要担心。

  • begin(monitor): 可选的。拖动操作开始时触发。不需要返回任何内容,但如果返回一个对象,它将覆盖item规范的默认属性。

  • end(item, monitor): 可选的。当拖动停止时,end被调用。对于每个begin呼叫,end保证相应的呼叫。您可以调用monitor.didDrop()以检查丢弃是否由兼容的放置目标处理。如果它被处理,并且放置目标通过从其方法返回普通对象来指定放置结果drop(),则它将可用作monitor.getDropResult()。此方法是触发Flux动作的好地方。注意:如果在拖动时卸载组件,则component参数设置为null

  • canDrag(monitor): 可选的。用它来指定当前是否允许拖动。如果您想要始终允许它,只需省略此方法即可。如果您想基于某些谓词禁用拖动,则指定它很方便props注意:您可能无法调用monitor.canDrag()此方法。

  • isDragging(monitor): 可选的。默认情况下,仅启动拖动操作的拖动源被视为拖动。您可以通过定义自定义isDragging方法来覆盖此行为。它可能会返回类似的东西props.id === monitor.getItem().id。如果在拖动过程中可以卸载原始组件并在以后使用其他父级“复活”,则执行此操作。例如,当在卡片板中的列表中移动卡时,您希望它保留拖动的外观 - 即使在技术上,组件也会被卸载,并且每次将其移动到另一个列表时都会安装另一个组件。注意:您可能无法调用monitor.isDragging()此方法。

  • collect: 可选的。收集功能。它应该返回一个普通的道具对象返回注入你的组件。它接收两个参数,monitorprops。阅读概述,了解监视器和收集功能的介绍。请参阅下一节中详细描述的收集功能。

 

useDrop 一个钩子,用于将当前组件用作放置目标。

参数

  • spec规范对象

返回值数组

  • Index 0:包含collect函数中收集的属性的对象。如果collect未定义任何函数,则返回空对象。
  • Index 1:放置目标的连接器功能。这必须附加到DOM的drop-target部分。

规范对象成员

  • accept:必填。一个字符串,一个ES6符号,一个数组或一个返回给定组件的函数的函数props。此放置目标仅对指定类型的拖动源生成的项目作出反应。

  • options: 可选的。一个普通的对象。如果组件的某些道具不是标量(即,不是原始值或函数),则arePropsEqual(props, otherProps)options对象内指定自定义函数可以提高性能。除非您遇到性能问题,否则不要担心。

  • drop(item, monitor): 可选的。在目标上放置兼容项目时调用。您可以返回undefined或普通对象。如果返回一个对象,它将成为放置结果,并且可以在其endDrag方法中作为拖动源使用monitor.getDropResult()。如果您希望根据接收到丢弃的目标执行不同的操作,这非常有用。如果您有嵌套的放置目标,则可以drop通过检查monitor.didDrop()和测试是否已经处理了嵌套目标monitor.getDropResult()。此方法和源endDrag方法都是触发Flux操作的好地方。如果canDrop()已定义并返回,则不会调用此方法false

  • hover(item, monitor): 可选的。当项目悬停在组件上时调用。您可以检查monitor.isOver({ shallow: true })以测试悬停是发生在当前目标上还是嵌套上。与drop()此不同,即使canDrop()定义并返回,也会调用此方法false。您可以检查monitor.canDrop()以测试是否是这种情况。

  • canDrop(item, monitor): 可选的。使用它来指定放置目标是否能够接受该项目。如果您想要始终允许它,只需省略此方法即可。如果你想基于某个谓词over props或者禁用删除,那么指定它是很方便的monitor.getItem()注意:您可能无法调用monitor.canDrop()此方法。

  • collect: 可选的。收集功能。它应该返回一个普通的道具对象返回注入你的组件。它接收两个参数,monitorprops,了解监视器和收集功能的介绍。请参阅下一节中详细描述的收集功能。

import React, { useRef } from 'react'
import { useDrag, useDrop } from 'react-dnd'
import ItemTypes from './ItemTypes';
const style = {
  padding: '0.5rem 1rem',
  marginBottom: '.5rem',
  backgroundColor: 'white',
  cursor: 'move',
}
const TopicList = ({ id, text, index, moveCard }) => {
  const ref = useRef(null)
  const [, drop] = useDrop({
    //定义拖拽的类型
    accept: ItemTypes.TOPIC,    
    hover(item, monitor) {
      //异常处理判断
      if (!ref.current) { 
        return
      }
      //拖拽目标的Index
      const dragIndex = item.index;
      //放置目标Index
      const hoverIndex = index; 
      // 如果拖拽目标和放置目标相同的话,停止执行
      if (dragIndex === hoverIndex) { 
        return
      }
      //如果不做以下处理,则卡片移动到另一个卡片上就会进行交换,下方处理使得卡片能够在跨过中心线后进行交换.
      //获取卡片的边框矩形
      const hoverBoundingRect = ref.current.getBoundingClientRect();    
      //获取X轴中点
      const hoverMiddleY =
        (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2; 
      //获取拖拽目标偏移量
      const clientOffset = monitor.getClientOffset();   
      const hoverClientY = clientOffset.y - hoverBoundingRect.top
      // 从上往下放置
      if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {  
        return
      }
      // 从下往上放置
      if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {  
        return
      }
      moveCard(dragIndex, hoverIndex);  //调用方法完成交换
      item.index = hoverIndex;  //重新赋值index,否则会出现无限交换情况
    },
  })
  const [{ isDragging }, drag] = useDrag({
    item: { type: ItemTypes.TOPIC, id, index },
    collect: monitor => ({
      isDragging: monitor.isDragging(),
    }),
  })
  const opacity = isDragging ? 0 : 1
  drag(drop(ref))
  return (
    <div ref={ref} style={{ ...style, opacity }}>
      <span style={{ float: 'left' }}>{index + 1}.</span>
      <div className='stem' dangerouslySetInnerHTML={{ __html: text }}></div>
    </div>
  )
}
export default TopicList

5.新建 ItemTypes.js

export default {
  TOPIC: 'topic'
}

注意:react的版本需要是react16的新版本,否则会报如下图所示的错误,具体兼容到几,未测试,但是之前的react 16.4.2是实现不了当前功能的,所以在开发前请确认react版本

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

react项目中使用react-dnd实现列表的拖拽排序 的相关文章

  • 微服务优点缺点

    微服务架构采用Scale Cube方法设计应用架构 将应用服务按功能拆分成一组相互协作的服务 每个服务负责一组特定 相关的功能 每个服务可以有自己独立的数据库 从而保证与其他服务解耦 耦合是指两个或两个以上的体系或两种运动形式间通过相互作用

随机推荐

  • 移动端按设计图1:1布局方法

    1 为什么要写这篇教程 移动端布局大多数前端工程师使用的是百分比布局 然而百分比布局造成了很多问题 比如图片在不同分辨率下会有变形的问题 高度需要按照分辨率去兼容适配等等 今天给大家分享的这种布局方式 可以摈弃百分比布局 直接根据设计图1
  • 管道符和xargs

    先看一个例子 今天上了一门Linux课 其中有一道题是这样的 将文件 lib 目录下所有以包含 so的文件复制到cmd test目录下 一开始看到这个题 想法是先用find命令找出包含 so的文件 然后使用管道符cp 如下 find lib
  • robotstudio要从当前占位符中提取IRB2600....

    如上图所示 在添加singal后重启控制器便出现了这样的提示 找了一圈也没有找到答案 希望有高人指点指点
  • 关于8266WiFi模块(AT)问题分析与解答(单片机和wifi模块连接)

    近段时间由于作品需要 就入手了一个esp 01 s 8266wifi模块 厂家已经刷好固件 这个模块使用起来还是很简单便捷的 但是在调试过程中会遇到各种问题 以下是个人的一个总结 希望对大家有帮助 1 单片机晶振和波特率问题 重要 有关单片
  • 基于预测控制模型的自适应巡航控制仿真与机器人实现(Matlab代码实现)

    目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码 1 概述 自适应巡航控制技术为目前由于汽车保有量不断增长而带来的行车安全 驾驶舒适性及交通拥堵等问题提供了一条有效的解决途径 因此本文通过理论分析 仿真验证及实车实验对自适应
  • 使用editor.md渲染markdown并自定义目录

    使用editor md渲染markdown并自定义目录 一 需求 最近在开发个人博客 在做文章详情页的时候 需要将markdown格式的文本字符串渲染成html页面 于是逛github的时候发现了这一款markdown在线编辑器 它支持将m
  • Json“牵手”亚马逊商品详情数据方法,亚马逊商品详情API接口,亚马逊API申请指南

    亚马逊平台是美国最大的一家网络电子商务公司 亚马逊公司是1995年成立 刚开始只做网上书籍售卖业务 后来扩展到了其他产品 现在已经是全世界商品品种最多的网上零售商和第二互联网公司 亚马逊是北美洲 欧洲等地区的主流购物平台 亚马逊商品分类接口
  • Office Visio 2007安装教程

    哈喽 大家好 今天一起学习的是Visio 2007的安装 这是一个绘制流程图的软件 用有效的绘图表达信息 比任何文字都更加形象和直观 Office Visio 是office软件系列中负责绘制流程图和示意图的软件 便于IT和商务人员就复杂信
  • SpringCloud与Dubbo的比较

    目录 Dubbo 一 dubbo简介 二 dubbo组织架构图 三 dubbo的优势 SpringCloud 一 SpringCloud简介 二 SpringCloud组织架构 三 SpringCloud特点 四 Dubbo与SpringC
  • 共模电感(扼流圈)选型

    1 共模电感原理 在介绍共模电感之前先介绍扼流圈 扼流圈是一种用来减弱电路里面高频电流的低阻抗线圈 为了提高其电感扼流圈通常有一软磁材料制的核心 共模扼流圈有多个同样的线圈 电流在这些线圈里反向流 因此在扼流圈的芯里磁场抵消 共模扼流圈常被
  • Python:打包生成.pyc、.pyd文件

    目录 pyd文件是什么 1 环境 2 待编译文件hello py以及setup py文件 3 运行调试 4 写在最后 pyd文件是什么 pyd文件类似于DLL 一般用C C 语言编译而成 可用作模块导入Python程序中 pyd文件仅适用于
  • 使用Unity游戏引擎在IOS模拟器中运行的方法

    在Unity编译IOS程序时 在Unity导航栏菜单中选择Edit gt ProjectSettings gt Player 菜单项 选择IOS平台在下方SDK Version处选择运行设备为IOS模拟器 选择完毕后Build and Ru
  • 任意代码执行漏洞简介

    一 任意代码执行漏洞思维导图 代码执行漏洞的成因 应用程序在调用一些能够将字符串转换为代码的函数 例如php中的eval中 没有考虑用户是否控制这个字符串 将造成代码执行漏洞 代码执行漏洞的常用函数 PHP eval assert preg
  • springcloud整合Hystrix

    作用 1 服务降级 触发情况 程序运行异常 超时 服务熔断触发服务降级 线程池 信号量打满也会触发服务降级 2 服务熔断 直接拒绝访问 即使有正确的访问也会短路 3 服务限流 排队有序进行 构建服务 1 建module provider h
  • 希沃白板5使用方法

    一 获取白板 手机和电脑都下载希沃白板五5 二 使用白板制作课件 1 获取课件 制作课件 方法一 1 点击课件库 2 点击右上角齿轮完成教材选择 3 找到所需课件 4 点击右下角箭头翻看 觉得可以点击 限免获取 5 点击云课件 找到刚才获取
  • .Net Core Json序列化和反序列化以及自定义JsonConverter来转化特殊日期时间格式

    System Text Json 命名空间提供用于序列化和反序列化 JavaScript 对象表示法 JSON 的功能 System Text Json 命名空间包含所有入口点和主要类型 System Text Json Serializa
  • ELK日志分析系统--Elasticserach安装

    ElK安装 安装es Elasticserach介绍 Elasticsearch是个开源分布式搜索引擎 提供搜集 分析 存储数据3大功能 特点有 分布式 零配置 自动发现 索引自动分片 索引副本机制 restful风格接口 多数据源 自动搜
  • 【Linux操作系统】【综合实验五 网络管理与通信】【更新中】

    文章目录 一 实验目的 二 实验要求 三 实验内容 四 实验报告要求 一 实验目的 要求了解和熟悉Linux网络客户 服务器管理模式 client server 与网络环境的配置 熟悉网络远程登录模式与TCP IP常见终端命令的使用 学会使
  • jmeter常见问题

    问题1 javax swing text BadLocationException Position not represented by view 解决方法 问题2 Could not instantiate class kg apc j
  • react项目中使用react-dnd实现列表的拖拽排序

    现在有一个新需求就是需要对一个列表 实现拖拽排序的功能 要实现的效果如下图 可以通过 react dnd 或者 react beautiful dnd 两种方式实现 今天先讲下使用react dnd是如何实现的 github地址 https