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.pswp.cn/news/696432.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/696432.shtml
英文地址,請注明出處:http://en.pswp.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;…