React Draggable 实现图片拖拽

news2025/7/21 11:00:53

React Draggable 实现拖拽

React Draggablereact 生态中,最好用的拖拽实现库之一。如果你的应用中需要实现拖拽功能,可以尝试用 react-draggable,它可以满足多数情况下的拖拽需求,比如一个弹出设置浮窗,可以相互遮挡的容器之类。在所有 react 拖拽库里(即 react dnd, drag and drop),react-draggable 算是把功能性和易用性平衡得最好的拖拽库了。

在实现卡拉云时,我们也大量使用了 react-draggable。所以这篇文章里,我们介绍如何使用 react-draggable,一些常见的设置和我们的经验。请根据下面的代码一步步实现,最终你要实现的效果如下
在这里插入图片描述

如果你在参考的过程中有不确定代码应该怎么写,可以直接到代码库中找到对应的文件。本文可参考的代码放在 github 上: react-draggable代码,觉得不错的话不妨打个星。

react-draggable 简介

react-draggable 经过几年的发展,已经是一个相对比较稳定的库了。从 npm trends 上看,从 16 年起它的流行程度就迅速超过了其它几个类似的项目。它在 github 上算非常热门的项目了,使用它的项目众多,所以可以放心地使用。如果有 bug 反馈也会非常快

如果看它的源码的话,会发现它的原理其实很简单,它只是将一个需要被拖拽的组件包到它定义的一个组件中,当鼠标拖拽时,重新计算组件的位置,这样就实现了“拖拽”的效果。这也是绝大多数拖拽组件库的实现方式。

准备项目

我们按常规,使用 create-react-app 这个工具来创建项目。如果你本地没有安装 npx 的话,强烈推荐,使用非常方便。

在准备好 react 脚手架后,你就可以到目录里,把项目跑起来。

执行 npm start。这时候应该看到一个熟悉的画面

在这里插入图片描述

当然如果你是在已有项目里准备加上 react-draggable,那么跳过本步,直接执行下一步安装就好了。

安装 react-draggable

现在执行 npm install react-draggable,执行完后应该在你的 node_modules 中就装好了 react-draggable

新建一个盒子组件

我们先在 App.js 文件中加上几个简单的结构,比如一个框用来表示需要拖拽的组件,同时在框上加上一个拖拽把手,这样方便用户识别。

App.js 中加上一个叫 Box 的组件先占位,如下

	import './App.css';
	 
	const Box = () => {
	  return <>hello world</>
	}
	 
	function App() {
	  return (
	    <div className="App">
	        <Box></Box>
	    </div>
	  );
	}
	 
	export default App;

注意,这里的 Box 只是非常简单地在屏幕上打一行字出来。

接着,我们把 Box 稍微完善一下,把它的 css 写得规整一点。如果你对 css 本身不熟悉,没有关系,直接复制 index.css 中的代码就可以了。

.box {
  background-color: green;
  width: 300px;
  height: 300px;
  display: flex;
  flex-direction: column;
}
 
.drag-handler {
  background-color: grey;
  height: 50px;
  cursor: move;
}

到这里,我们应该已经可以看见基本成型的一个盒子组件。注意当鼠标移到把手上时,会出现拖拽的指针指示,这样可以提示用户这是一个可拖拽组件。

接入 react-draggable

现在,我们希望当用户鼠标拖拽把手时,把手本身可以被移动。首先我们把 react-draggable 导入

import Draggable from 'react-draggable'; 

到这里,App.js 中就是。

import './App.css';
import Draggable from 'react-draggable'; // The default
 
const Box = () => {
  return <div className="box">
    <div className='drag-handler'>拖这里可以</div>
    <div>box 正文,拖这里拖不动</div>
  </div>
}
 
function App() {
  return (
    <div className="App">
      <Draggable>
        <Box></Box>
      </Draggable>
 
    </div>
  );
}
 
export default App;

但是千万注意,如果这里你去试图拖拽一下把手,是拖不动的。原因是 Draggable 并不能直接包一个组件,而需要再包一层 div。我一开始在这里卡了很久时间,但解决的办法很简单,只需要多包一层 div 在外面即可。

function App() {
  return (
    <div className="App">
      <Draggable>
        <div>
          <Box />
        </div>
      </Draggable>
 
    </div>
  );
}

可以看到,如果这时候开始拖动,Box 就可以在界面上自由移动了。但是有一个问题,我们不希望用户拖动正文部分时,也将组件拖动。

在这里插入图片描述

要解决这个问题也很简单,请看下一章

如何在 react-draggable 中仅允许组件的一部分被拖动

react-draggableAPI 中,一个属性叫 handle,这个属性的作用就是用来选出对拖动有反应的组件部分。

对应到我们上面的例子,我们只希望在用户拖动把手时,整个组件移动。所以我们只需要用 handle 属性,选出来把手即可。我们在代码中加入

function App() {
  return (
    <div className="App">
      <Draggable handle='.drag-handler'>
        <div>
          <Box />
        </div>
      </Draggable>
 
    </div>
  );
}

注意这里,.drag-handler 是一个选择器,用来选出 className=drag-handler 的组件部分,也就是对应的我们的把手。

那么到此,组件就只能通过拖动把手而拖动了。

在这里插入图片描述

限制可拖动范围

有时候我们希望限制可以拖动的范围,比如你不希望用户把一个组件拖到另一个区域,因为可能挡住那个区域的其它界面。在 react-draggable 中,要限制拖动范围很简单,只需要给定 bounds 属性就可以了。

bounds: {left?: number, top?: number, right?: number, bottom?: number} | string,

这个 bounds 属性可以指定屏幕上上下左右四个位置的边界限制,同时你也可以给一个字符串,用来选择组件的父组件,这样可以限制该组件只能在它的父组件中移动。限制在父组件中的情况较多,比如你在做一个扑克牌游戏时,显然只希望扑克牌只在牌桌上被拖动,那么你就可以限制扑克牌,让它始终在父组件牌桌中。

具体的例子这里就不展开讲了,请自行探索。

调整样式

最后我们稍微调整一下样式,让整个 APP 看起来漂亮一些。到此,你应该就已经学会使用 react-draggable 来实现拖拽操作了

在这里插入图片描述

总结
react-draggable 总体来说是一个非常优秀的拖拽库,虽然自己写也不需要太多代码,但使用一个“经历过战场”的组件库还是可以省掉不少自己实现的时间。同时它的 API 足够优秀,可以满足日常工作需要。如果你觉得自己写有太大挑战,尝试一下用卡拉云搭建后台工具,事半功倍。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/368595.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2月更新!EasyOps又迎来新升级,解锁9大新特性

又到了每月产品盘点时刻&#xff0c;9大新功能上线和升级优化&#xff0c;涉及Hyperlnsight超融合持续观测平台、CMDB立体化资源管理平台、DevOps持续交付平台、AutoOps自动化运维平台、EasyHub资源共享平台&#xff0c;在不断的技术创新过程中&#xff0c;进一步加速IT运维效率…

Android framework socketpair

简述 在Linux中&#xff0c;socketpair函数可以用于创建一对相互连接的、通信域为AF_UNIX的套接字&#xff0c;其中一个套接字可用于读取&#xff0c;另一个套接字可用于写入。可以使用这对套接字在同一进程内进行进程间通信&#xff08;IPC&#xff09;。 以下是使用socketp…

python 学习

1.转义字符 字符串前加r&#xff0c;使转义字符不起作用 print(r"hello\t world") 2.数据类型 python数据类型分为int,float,bool,str 整数类型的形式: print("二进制0b开头", 0b10111001) print("八进制0o开头", 0o1257436) print("…

Unable to connect to Redis无法连接到Redis

文章目录项目场景&#xff1a;问题描述原因分析&#xff1a;解决方案&#xff1a;项目场景&#xff1a; 提示&#xff1a;这里简述项目相关背景&#xff1a; 在某个项目中的提交按钮不好用 org.springframework.data.redis.RedisConnectionFailureException: Unable to con…

【线程基础篇】

进程 进程本质是一个正在执行的程序。程序运行时&#xff0c;系统会创建进程&#xff0c;并给进程分配独立的内存空间。 CPU时间片切换 CPU时间片切换时&#xff0c;进程需要从切换之前运行的位置开始执行&#xff0c;所以进程还包括程序计数器、堆栈指针。 单核CPU时&…

如何拼接字符串-探究“+号拼接”/“StringBuilder”在不同场景下的效率问题

拼接字符串&#xff0c;在程序开发中很常见也很常用&#xff0c;大家都会&#xff1a;号拼接String.concat(String str)StringBuffer / StringBuilder但这里今天主要探究“号拼接”&#xff0c;“StringBuilder”在不同场景下的效率问题。不都说 StringBuilder 在处理字符串拼接…

保持超低温环境新方法:功耗降至十分之一!

&#xff08;图片来源&#xff1a;网络&#xff09;量子比特是量子计算机的主要构建部分&#xff0c;然而热量会导致量子比特容易出错&#xff0c;因此量子系统通常保存在超低温稀释制冷机内&#xff0c;可以将温度保持在绝对零度&#xff08;−273.15℃&#xff09;以上。但是…

消费复苏迎“春”暖,服装行业如何开启“狂飙”模式?

2023年开年前2个月&#xff0c;全国多地消费市场的“热度”一直在持续上涨&#xff0c;商场、餐馆、娱乐场所等消费市场人气旺盛&#xff0c;消费复苏的“暖”意十足&#xff0c;一幕幕“忙”起来、“热”起来的场景&#xff0c;让各行各业的商家都对未来充满了期待与信心。在消…

基于SpringBoot的外卖项目的优化

基于SpringBoot的外卖项目的优化1、缓存优化1.1、缓存短信验证码问题分析代码改造1.2、缓存菜品数据实现思路1.3、Spring Cache介绍常用注解CachePutCacheEvictCacheable使用方式1.4、缓存套餐数据实现思路代码改造2、读写分离2.1、主从复制存在的问题介绍配置配置主库--master…

获取浏览器硬件资源的媒体数据(拍照、录音、录频、屏幕共享)

目录一、window.navigator 对象包含有关访问者浏览器的信息取二、MediaDevices1.使用麦克风2.使用摄像头&#xff08;和音频一样&#xff09;3.拍照4.录屏三、MediaRecorder(录制,可录制音频视屏)一、window.navigator 对象包含有关访问者浏览器的信息取 <!DOCTYPE html>…

YZRJ面试

面试过程目录概述需求&#xff1a;设计思路实现思路分析1.自我介绍之类的2.http 和https 协议的区别3.进程和线程的区别4.vm 安装的nginx 和Mysql5.评价拓展实现参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfect code,full bu…

自然语言处理(NLP)之求近义词和类比词<MXNet中GloVe和FastText的模型使用>

这节主要就是熟悉MXNet框架中的两种模型&#xff1a;GloVe和FastText的模型(词嵌入名称)&#xff0c;每个模型下面有很多不同的词向量&#xff0c;这些基本都来自wiki维基百科和twitter推特这些子集预训练得到的。我们只需要导入mxnet.contrib中的text模块即可&#xff0c;这里…

模拟百度翻译-课后程序(JAVA基础案例教程-黑马程序员编著-第六章-课后作业)

【案例6-5】 模拟百度翻译 【案例介绍】 1.任务描述 大家对百度翻译并不陌生&#xff0c;本案例要求编写一个程序模拟百度翻译。用户输入英文之后搜索程序中对应的中文&#xff0c;如果搜索到对应的中文就输出搜索结果&#xff0c;反之给出提示。本案例要求使用Map集合实现英…

C/C++开发,无可避免的内存管理(篇一)-约束好跳脱的内存

一、养成内存管理好习惯 1.1 养成动态对象创建、调用及释放好习惯 开发者手动接管内存分配时&#xff0c;必须处理这两个任务。分配原始内存时&#xff0c;必须在该内存中构造对象&#xff1b;在释放该内存之前&#xff0c;必须保证适当地撤销这些对象。如果你的项目是c项目&am…

windows、linux系统设置404教程(适用虚拟主机)

设置一个好的自定义错误页面&#xff0c;可以增加网站的收录&#xff0c;挽留住一些可能因打不开的页面而放弃的客户&#xff0c;我司虚拟主机特别提供了自定义错误页面设置&#xff0c;包括404错误在内的所有自定义错误都可以设置。 linux系统设置方法&#xff1a; 第一步:在…

mysql 内存架构

1. 背景 从 innodb 的整体架构中可以知道 innodb 的内存架构中分为 buffer pool 缓存区, change pool 修改缓冲区, adaptive hash index 自适应哈希索引, 和 log buffer 日志缓冲区. 2. buffer pool buffer pool 是用于缓冲磁盘页的数据&#xff0c;mysql 的80%的内存会分配给…

通过cfssl自签证书https证书

背景 公司内部自建Web服务&#xff0c;通过自签CA&#xff0c;然后签发https证书 工具地址: GitHub - cloudflare/cfssl: CFSSL: Cloudflares PKI and TLS toolkit 使用步骤: 1. 在release页面中下载最新的二进制包&#xff0c;我使用的是1.5的解压并重命名二进制文件 tar…

Idea集成码云

1&#xff1a;Idea集成码云1.1&#xff1a;IDEA安装码云插件【第一步】Idea 默认不带码云插件&#xff0c; 我们第一步要安装 Gitee 插件。如图所示&#xff0c; 在 Idea 插件商店搜索 Gitee&#xff0c;然后点击右侧的 Install 按钮。安装成功后&#xff0c;重启 Idea。Idea 重…

复旦团队发布国内首个模型MOSS 类ChatGPT

复旦团队发布国内首个模型MOSS 类ChatGPT 首先看到这个标题&#xff0c;还有这个名字&#xff0c;我是正经&#xff08;zhen jing&#xff09;的 &#xff08;bu shi 流浪地球&#xff1f;550W&#xff1f;不了解的可以把550W倒过来写&#xff0c;就懂了 看到新闻里的一些图…

Interview系列 - 07 Java | 集合的快速失败和安全失败机制 | 迭代器类源码 | CopyOnWriteArrayList

文章目录1. 集合的快速失败 (fail-fast)1. 使用增强for遍历集合并使用ArrayList的 remove() 方法删除集合元素2. 使用 forEach 遍历集合并使用ArrayList的 remove() 方法删除集合元素3. 使用迭代器遍历集合并使用ArrayList的 remove() 方法删除集合元素4. 使用迭代器遍历集合并…