React 模态框的设计(一)拖动组件的设计

春节终结束了,忙得我头疼。终于有时间弄自己的东西了。今天来写一个关于拖动的实例讲解。先看效果:
在这里插入图片描述

这是一个简单的组件设计,如果用原生的js设计就很简单,但在React中有些事件必须要多考虑一些。这是一个系列的文章,专门针对实际应用开发过程中的技术难点逐个讲解,相信大家能用得着。
再次说明,我的示例都是基于MUI框架的,如果你不讲究样式的话,也可以直接采用原生dom的样式设计。关于项目的创建及MUI的应用请查看我以往的文章,都是详细的教程讲解。

要点解说

设计的思路是只把把要移动的组件进行包裹就可以对其进行拖动,注意是拖动,(不是拖放,我后期会出一个拖放的技术文章,请大家另行期待)

第一步: 首先是触发机制,当在目标组件上按下左键时开始拖动,所以要有个标记记录拖动的状态。

const [isDragging, setIsDragging] = useState(false);

当按下左键时设置为 true, 放开时设置为false

// 鼠标按下左键时的事件
const handleMouseDown = (event) => {if (event.button !== 0) return;  // 按下的不是左键则直接返回。setIsDragging(true);
};// 鼠标放开左键时的事件
const handleMouseUp = (event) => {if(event.button !== 0) return;setIsDragging(false);
};

第二步: 单击左键时要记录下鼠标的位置信息,我们定义一个state来记录这个值:

const offsetX = useRef(0);
const offsetY = useRef(0);

第三步: 单击左键不放进行移动,要记录下相对于position的变化量。因为要把这个变化反应到UI上,所以要用useState:

const [position, setPosition] = useState({ x: 0, y: 0 });

继续下面的代码:

// 鼠标按下左键时的事件
const handleMouseDown = (event) => {if (event.button !== 0) return;offsetX.current = event.clientX - position.x;offsetY.current = event.clientY - position.y;setIsDragging(true);
};// 鼠标移动事件
const handleMouseMove = (event) => {if (isDragging) {setPosition({x: event.clientX - offsetX.current,y: event.clientY - offsetY.current});}
};

或许你会想直接把这些事件绑定到要拖动的组件上就行了,但这里有个问题,有时我们拖着拖着由于速度过快,鼠标就移出了组件,这就达不到我们的设计效果了。所以呢,我们要把相应的事件绑定到document上是最靠谱的。我们只要把触发事件绑定到拖动组件上就可以了。

if (isDragging) {document.addEventListener('mousemove', handleMouseMove);document.addEventListener('mouseup', handleMouseUp);
} else {document.removeEventListener('mousemove', handleMouseMove);document.removeEventListener('mouseup', handleMouseUp);
}

document上绑定的事件在组件卸载后还要移除,所以我们用到useEffect,完整的代码如下:

import React, { useEffect, useRef, useState } from 'react';export default function Draggable({children}) {const [isDragging, setIsDragging] = useState(false);const [position, setPosition] = useState({ x: 0, y: 0 });const offsetX = useRef(0);const offsetY = useRef(0);useEffect(() => {const handleMouseMove = (event) => {if (isDragging) {setPosition({x: event.clientX - offsetX.current,y: event.clientY - offsetY.current});}};const handleMouseUp = (event) => {if(event.button !== 0) return;setIsDragging(false);};if (isDragging) {document.addEventListener('mousemove', handleMouseMove);document.addEventListener('mouseup', handleMouseUp);} else {document.removeEventListener('mousemove', handleMouseMove);document.removeEventListener('mouseup', handleMouseUp);}return () => {document.removeEventListener('mousemove', handleMouseMove);document.removeEventListener('mouseup', handleMouseUp);};}, [isDragging]);const handleMouseDown = (event) => {event.preventDefault();event.stopPropagation();if (event.button !== 0) return;offsetX.current = event.clientX - position.x;offsetY.current = event.clientY - position.y;setIsDragging(true);};return (<divstyle={{position: 'relative',userSelect: 'none',cursor: isDragging ? 'grabbing' : 'grab',transform: `translate(${position.x}px, ${position.y}px)`}}onMouseDown={handleMouseDown}>{children}</div>);
}

这样一个基本的拖动组件就设计完成了。快试试效果吧。

import React from "react";
import Draggable from "../framework-kakaer/SModel/_Dragable";
import Box from "@mui/material/Box";
import Stack from "@mui/material/Stack";
import Typegraphy from "@mui/material/Typography";function DraggableTest() {return (<Boxsx={{display: 'flex',flexDirection: 'column',alignItems: 'center',justifyContent: 'center',height: '100vh',}}><Stack spacing={2}><Typegraphy variant="h4">拖动组件设计测试</Typegraphy><Draggable><Box sx={{ width: 100, height: 100, bgcolor: 'red' }} /></Draggable><Draggable><Box sx={{ width: 100, height: 100, bgcolor: 'blue' }} /></Draggable></Stack></Box>)
}export default DraggableTest;

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

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

相关文章

SpringBoot3整合elasticsearch8

版本 SpringBoot 3.0 Elasticsearch 8.12.1 依赖 我使用的 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency> 还可以用&#xff0c;但我没用…

YOLOv9来咧!

文章目录 论文:主要内容一、提出使用PGI&#xff08;Programmable Gradient Information&#xff0c;可编程梯度信息&#xff09;来解决信息瓶颈问题和深度监督机制不适合轻量级神经网络的问题。二、设计了GELAN&#xff08;Generalized ELAN &#xff0c;广义ELAN&#xff09;…

LLM 模型融合实践指南:低成本构建高性能语言模型

编者按&#xff1a;随着大语言模型技术的快速发展&#xff0c;模型融合成为一种低成本但高性能的模型构建新途径。本文作者 Maxime Labonne 利用 mergekit 库探索了四种模型融合方法&#xff1a;SLERP、TIES、DARE和passthrough。通过配置示例和案例分析&#xff0c;作者详细阐…

Ansible playbook 剧本部署WEB NFS rsync sersync(及时监控)架构

ansible playbook剧本介绍&#xff1a; playbook 是ansible用于配置&#xff0c;部署和管理被节点的剧本 由一个或多个模块组成&#xff0c;完成统一的目的&#xff0c;实现自动化操作 剧本编写需遵循yaml语法 yaml的三要素&#xff1a; 缩进&#xff1a;两个字符&#xff0c;默…

【Vue3】toRefs和toRef在reactive中的一些应用

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

快速上手vue指南

Vue.js 是一款非常流行且易于上手的前端框架&#xff0c;用于构建用户界面和单页应用程序&#xff08;SPA&#xff09;。它以其简洁的API、灵活的组件系统和高效的性能著称。如果你是初学者&#xff0c;以下是一些关键步骤和建议&#xff0c;可以帮助你快速上手 Vue.js。 1. 理…

【Qt】实现 Ctrl + 鼠标滚轮 缩放文本功能

【Qt】实现 Ctrl 鼠标滚轮 缩放文本功能 文章目录 I - 实现自定义控件II - 完整代码III - 参考链接 I - 实现自定义控件 主要原理 继承 QTextEdit 或者 QPlainTextEdit 类&#xff0c;重写滚轮事件 wheelEvent, QTextEdit 和 QPlainTextEdit 中均包含此函数 头文件 TextEdit…

学习springMVC第二天

REST简介 REST(Representational State Transfer)&#xff0c;表现形式状态转换 传统风格资源描述形式 http://localhost/user/getById?id1 http://localhost/user/saveUser REST风格描述形式 http://localhost/user/1 http://localhost/user 优点&#xff1a; 隐藏资源的访问…

C++模板->模板的概念、函数模板基本语法、函数模板注意事项、普通函数与函数模板区别、普通函数与函数模板调用规则、模板的局限性

#include<iostream> using namespace std; //交换两个整型函数 void swapInt(int& a, int& b) { int temp a; a b; b temp; } //交换两个浮点型函数 void swapDouble(double& a, double& b) { double temp a; a b; b te…

MATLAB中gtext函数用法

目录 语法 说明 示例 使用鼠标将文本添加到图窗 指定字体大小和颜色 在创建后修改文本 gtext函数的功能是使用鼠标将文本添加到图窗。 语法 gtext(str) gtext(str,Name,Value) t gtext(___) 说明 gtext(str) 在使用鼠标选择的位置插入文本 str。当将鼠标指针悬停在图…

Oracle普通用户启停JOB报错ORA 27486权限不足

Oracle普通用户启停JOB报错ORA 27486权限不足 问题与现象原因与对策 问题与现象 应用用户通过DBMS_SCHEDULER启停自己的JOB需要的权限&#xff1a; grant execute on dbms_scheduler to appuser;该普通用户有CREATE JOB的权限。通过DBMS_SCHEDULER停止自己的JOB时&#xff1a…

3个wordpress中文企业主题模板

农业畜牧养殖wordpress主题 简洁大气的农业畜牧养殖wordpress主题&#xff0c;农业农村现代化&#xff0c;离不开新农人、新技术。 https://www.jianzhanpress.com/?p3051 老年公寓wordpress主题 浅绿色简洁实用的老年公寓wordpress主题&#xff0c;适合做养老业务的老年公…

高标准农田仪器设备

在当今社会中&#xff0c;农业已经逐渐走向了一条科技化、智能化的道路。高标准农田建设成为了现代化农业发展的一个重要方向。为了更好地提高农产品的产量和品质&#xff0c;科技人员们不断地在农田设备上进行创造性的改进与升级&#xff0c;以达到更加高效、节能、环保、智能…

SouthLeetCode-打卡24年02月第3周

SouthLeetCode-打卡24年02月第3周 // Date : 2024/02/12 ~ 202X/02/18 049.反转字符串 (1) 题目描述 049#LeetCode.344.简单题目链接#Monday2024/02/12 编写一个函数&#xff0c;其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。 不要给另外的数组分…

【C语言】注释

&#x1f388;个人主页&#xff1a;豌豆射手^ &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;C语言 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进步&…

计算机网络--物理层练习题

习题 下列说法正确的是&#xff08;D&#xff09; A 信道与通信电路类似&#xff0c;一条可通信的电路往往包含一个信道 信道不等于通信电路&#xff0c;一条可双向通信的电路往往包含两个信道&#xff1a;一个是发送信道&#xff0c;一条是接收信道。另外&#xff0c;多个通…

【国际化】用JQuery-i18next的国际化demo,引入json

参考&#xff1a; 使用 i18next 的 jQuery 国际化 &#xff08;i18n&#xff09; 渐进式指南 (locize.com) i18next-http-backend/example/jquery/index.html at master i18next/i18next-http-backend (github.com) 文档 可能需要解决一下跨域问题&#xff0c;因为浏览器读取本…

Unity学习之Unity中的MVC思想

文章目录 1 前言2 MVC的基本概念3 不使用MVC思想制作UI逻辑3.1 拼面板3.2 面板脚本3.3 角色面板逻辑3.4 角色升级 4 使用MVC思想制作UI逻辑4.1 Model数据脚本4.2 View界面脚本4.2.1 MainView主界面4.2.2 RoleView 角色面板界面 4.3 Controller业务逻辑脚本4.3.1 MainController…

【开源软件????】

开源软件的影响力在当今的科技领域越来越显著&#xff0c;它已经成为软件开发的主流趋势之一。开源软件具有开放源代码、可免费使用、可自由分发等特点&#xff0c;这使得它在全球范围内得到了广泛的应用和支持。本文将围绕开源软件如何推动技术创新、开源软件的商业模式、开源…

phaseDNN文章解读

文章DOI: https://doi.org/10.48550/arXiv.1905.01389 作者是 Southern Methodist University 的Wei Cai 教授 A Parallel Phase Shift Deep Neural Network for Adaptive Wideband Learning 一种并行移相深度神经网络来自适应学习宽带频率信号 20190514 核心思想&#xff1a;…