react+antd 可拖拽模態框組件

DraggableModal 可拖拽模態框組件使用說明

概述

DraggableModal 是一個基于 @dnd-kit/core 實現的可拖拽模態框組件,允許用戶通過拖拽標題欄來移動模態框位置。該組件具有智能邊界檢測功能,確保模態框始終保持在可視區域內。

功能特性

  • ? 可拖拽移動:支持通過鼠標拖拽移動模態框位置
  • ? 智能邊界檢測:防止模態框被拖拽到屏幕可視區域外
  • ? 響應式適配:根據窗口大小自動調整可拖拽范圍
  • ? 平滑交互:使用 CSS transform 實現流暢的拖拽動畫
  • ? 類型安全:完整的 TypeScript 類型支持

安裝依賴

確保項目中已安裝以下依賴:

npm install @dnd-kit/core @dnd-kit/utilities
# 或
yarn add @dnd-kit/core @dnd-kit/utilities

基本用法

1. 導入組件

import DraggableModal from './components/DraggableModal';

2. 基礎示例

import React, { useState } from 'react';
import { Modal } from 'antd';
import DraggableModal from './components/DraggableModal';const ExampleComponent: React.FC = () => {const [visible, setVisible] = useState(false);return (<><button onClick={() => setVisible(true)}>打開可拖拽模態框</button><Modaltitle="可拖拽的模態框"open={visible}onCancel={() => setVisible(false)}modalRender={(modal) => (<DraggableModal>{modal}</DraggableModal>)}><p>這是一個可以拖拽的模態框內容</p></Modal></>);
};export default ExampleComponent;

3. 與 Antd Modal 結合使用

import React, { useState } from 'react';
import { Modal, Form, Input, Button } from 'antd';
import DraggableModal from '@/pages/StdFormEdit/components/DraggableModal';const FormModal: React.FC = () => {const [visible, setVisible] = useState(false);const [form] = Form.useForm();const handleSubmit = async () => {try {const values = await form.validateFields();console.log('表單數據:', values);setVisible(false);} catch (error) {console.error('表單驗證失敗:', error);}};return (<><Button type="primary" onClick={() => setVisible(true)}>打開表單模態框</Button><Modaltitle="用戶信息編輯"open={visible}onCancel={() => setVisible(false)}footer={[<Button key="cancel" onClick={() => setVisible(false)}>取消</Button>,<Button key="submit" type="primary" onClick={handleSubmit}>確定</Button>]}modalRender={(modal) => (<DraggableModal>{modal}</DraggableModal>)}><table ...></Modal></>);
};export default FormModal;

API 說明

DraggableModal Props

屬性類型默認值說明
childrenReactNode-需要包裝的模態框內容

組件內部實現細節

DraggableWrapper Props
屬性類型說明
topnumber模態框垂直位置偏移量
leftnumber模態框水平位置偏移量
childrenReactNode子組件內容
modalRefRefObject<HTMLDivElement>模態框DOM引用

技術實現

核心特性

  1. 拖拽識別:自動識別具有 modal-header 類名的元素作為拖拽手柄
  2. 邊界限制
    • 垂直方向:上邊界 -100px,下邊界為窗口高度減去模態框高度再減去100px
    • 水平方向:限制在窗口寬度范圍內,保持模態框居中對稱
  3. 位置計算:使用 CSS transform 屬性實現位置變換,性能優異

邊界檢測算法

// 垂直邊界檢測
const needRemoveMinHeight = -100; // 上邊界
const needRemoveMaxHeight = winH - 100 - modalRef.current.clientHeight; // 下邊界// 水平邊界檢測  
const needRemoveWidth = (winW - modalRef.current.clientWidth) / 2; // 左右對稱邊界

使用注意事項

1. 模態框結構要求

確保被包裝的模態框包含具有 modal-header 類名的標題欄元素:

// ? 正確 - Antd Modal 自動包含 modal-header 類名
<Modal title="標題">內容</Modal>// ? 錯誤 - 自定義模態框缺少 modal-header 類名
<div className="custom-modal"><div className="title">標題</div> {/* 缺少 modal-header 類名 */}<div>內容</div>
</div>

2. 性能優化建議

  • 避免在 DraggableModal 內部頻繁更新狀態
  • 對于復雜內容,建議使用 React.memo 優化子組件渲染
const OptimizedContent = React.memo(() => {return (<div>{/* 復雜內容 */}</div>);
});<DraggableModal><Modal title="優化示例"><OptimizedContent /></Modal>
</DraggableModal>

DraggableModal源碼

import React, { useState, useRef, useLayoutEffect } from 'react';
import { DndContext, useDraggable } from '@dnd-kit/core';
import type { Coordinates } from '@dnd-kit/utilities';const DraggableWrapper = (props: any) => {const { top, left, children: node, modalRef } = props;const { attributes, isDragging, listeners, setNodeRef, transform } = useDraggable({id: 'draggable-title'});const dragChildren = React.Children.map(node.props.children, (child) => {if (!child) {return child;}if (child.type === 'div' && child.props?.className?.indexOf('modal-header') >= 0) {return React.cloneElement(child, {'data-cypress': 'draggable-handle',style: { cursor: 'move' },...listeners});}return child;});let offsetX = left;let offsetY = top;if (isDragging) {offsetX = left + (transform?.x ?? 0);offsetY = top + transform?.y;}return (<divref={(el) => {setNodeRef(el);if (modalRef) modalRef.current = el;}}{...attributes}style={{transform: `translate(${offsetX ?? 0}px, ${offsetY ?? 0}px)`} as React.CSSProperties}>{React.cloneElement(node, {}, dragChildren)}</div>);
};const DraggableModal = (props: any) => {const [{ x, y }, setCoordinates] = useState<Coordinates>({x: 0,y: 0});const modalRef = useRef<HTMLDivElement>(null);const [modalSize, setModalSize] = useState({ width: 0, height: 0 });useLayoutEffect(() => {if (modalRef.current) {const rect = modalRef.current.getBoundingClientRect();setModalSize({ width: rect.width, height: rect.height });}}, [props.children]);return (<DndContextonDragEnd={({ delta }) => {const winW = window.innerWidth;const winH = window.innerHeight;const needRemoveMinHeight = -100;const needRemoveWidth = (winW - modalRef.current.clientWidth) / 2;const needRemoveMaxHeight = winH - 100 - modalRef.current.clientHeight;const newX = x + delta.x;const newY = y + delta.y;let curNewY = newY;if (newY < 0) {curNewY = newY < needRemoveMinHeight ? needRemoveMinHeight : newY;} else {curNewY = newY > needRemoveMaxHeight ? needRemoveMaxHeight : newY;}if (Math.abs(newX) < needRemoveWidth) {setCoordinates({x: newX,y: curNewY});} else {setCoordinates({x: newX < 0 ? 0 - needRemoveWidth : needRemoveWidth,y: curNewY});}}}><DraggableWrapper top={y} left={x} modalRef={modalRef}>{props.children}</DraggableWrapper></DndContext>);
};export default DraggableModal;

3. 兼容性說明

  • 支持現代瀏覽器(Chrome 88+、Firefox 84+、Safari 14+)
  • 移動端暫不支持拖拽功能
  • 需要 React 16.8+ 版本支持

故障排除

常見問題

Q: 模態框無法拖拽?

A: 檢查以下幾點:

  1. 確保模態框標題欄包含 modal-header 類名
  2. 確認 @dnd-kit/core 依賴已正確安裝
  3. 檢查是否有其他元素阻止了拖拽事件

Q: 拖拽時出現跳躍現象?

A: 這通常是由于 CSS 樣式沖突導致,確保沒有其他 transform 樣式影響模態框定位。

Q: 模態框被拖拽到屏幕外?

A: 組件內置了邊界檢測,如果出現此問題,請檢查窗口大小變化時是否正確觸發了重新計算。

版本歷史

  • v1.0.0: 初始版本,支持基礎拖拽功能和邊界檢測

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/90009.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/90009.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/90009.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

MySQL的基本操作及相關python代碼

下面為你介紹 MySQL 的基本操作,以及對應的 Python 代碼實現。我會先介紹 SQL 基本操作,再展示如何用 Python 連接 MySQL 并執行這些操作。 一、MySQL 基本操作(SQL 語句) 1. 連接數據庫 bash mysql -u root -p2. 創建數據庫 sql CREATE DATABASE testdb;3. 使用數據…

Armbian(斐訊N1)安裝xfce桌面以及遠程環境

安裝xfce桌面以及vncserver(遠程連接) 安裝xfce桌面 apt-get install xfce4 xfce4-goodies xorg dbus-x11 x11-xserver-utils ubuntu的安裝gdm3&#xff0c; apt install gdm3 debian安裝lightdm。 apt install lightdm 安裝vnc server apt-get install tightvncserver 中文字體…

【Oracle】Oracle 11g打補丁時遇到opatch apply命令無法識別

?? 1. 使用完整路徑執行命令 問題原因&#xff1a;若未將$ORACLE_HOME/OPatch加入系統PATH環境變量&#xff0c;直接輸入opatch apply會因系統無法定位命令而報錯。 解決方案&#xff1a; 改用絕對路徑執行&#xff1a; $ORACLE_HOME/OPatch/opatch apply例如&#xff1a; /u…

單例模式詳細講解

一.定義單例模式是一種創建型設計模式&#xff0c;確保一個類只有一個實例&#xff0c;并提供一個全局訪問點特點&#xff1a;1.構造函數和析構函數私有化2.禁用拷貝構造函數和賦值運算符重載&#xff08;delete&#xff09;3.利用靜態成員函數和靜態成員變量來給外界提供訪問二…

KORGym:評估大語言模型推理能力的動態游戲平臺

KORGym&#xff1a;評估大語言模型推理能力的動態游戲平臺 現有評估基準多受領域限制或 pretraining 數據影響&#xff0c;難以精準測LLMs內在推理能力。KORGym平臺應運而生&#xff0c;含50余款游戲&#xff0c;多維度評估&#xff0c;本文將深入解析其設計、框架、實驗及發現…

ISPDiffuser文章翻譯理解

ISPDiffuser: Learning RAW-to-sRGB Mappings with Texture-Aware Diffusion Models and Histogram-Guided Color Consistency翻譯 Type: Conference paper Author: Yang Ren1,4, Hai Jiang1,4, Menglong Yang1,2,?, Wei Li1,2, Shuaicheng Liu3,4,? Select: ???????…

C++線程池執行步驟分析,總結線程池流程

線程池流程總結&#xff1a;1、構造函數中創建線程&#xff0c;并添加到線程池&#xff08;構造函數返回時&#xff0c;線程自動啟動&#xff0c;并停在等待wait&#xff1a;從線程池取出一個任務處&#xff09;&#xff1b; 2、主線程中添加任務&#xff0c;到任務隊列。并用“…

Java 通過 HttpURLConnection發送 http 請求

問題&#xff1a; 在調試 kill 接口的時候&#xff0c;對方的服務用的是 Django RestFramework 框架提供的接口&#xff0c;用 python 請求時得到的內容如下&#xff1a; ? ~ python3 test.py <Response [200]> "true" // 對應的代碼是 print(response, r…

【PTA數據結構 | C語言版】列出連通集

本專欄持續輸出數據結構題目集&#xff0c;歡迎訂閱。 文章目錄題目代碼題目 給定一個有 n 個頂點和 m 條邊的無向圖&#xff0c;請用深度優先遍歷&#xff08;DFS&#xff09;和廣度優先遍歷&#xff08;BFS&#xff09;分別列出其所有的連通集。假設頂點從 0 到 n?1 編號。…

GoLang教程005:switch分支

3.4 Switch分支 在 GoLand&#xff08;其實是 JetBrains 開發的 Go 編程語言 IDE&#xff09;中&#xff0c;switch 是 Go 語言&#xff08;Golang&#xff09; 的一個重要控制結構&#xff0c;用于替代多個 if-else 語句。 ? 特點說明特性說明自動 breakGo 的 switch 語句默認…

uniapp相關地圖 API調用

目錄 一、 注意事項&#xff1a; manifest.json需增加配置 二、獲取用戶收貨地址 [uni.chooseAddress] 三、獲取當前的地理位置、速度 [uni.getLocation] 四、打開地圖選擇位置、查看位置(導航) [uni.chooseLocation] [uni.openLocation] 五、使用騰訊地圖逆地址解析接口實…

Java學習----NIO模型

在 Java 的 I/O 模型中&#xff0c;NIO&#xff08;Non - Blocking I/O&#xff0c;非阻塞 I/O&#xff09;是對 BIO 的重要改進。它為高并發場景提供了更高效的處理方式&#xff0c;在眾多 Java 應用中發揮著關鍵作用。NIO模型的核心在于非阻塞和多路復用&#xff0c;其采用 “…

MySQL計數函數count原理分析

前言 統計表中數據的條數是非常常用的操作,但是咱們常用的InnoDB存儲引擎計數函數是現時統計的,所以會出現性能的問題,這次我準備分享計數函數count的原理,保證之后遇到計數方面的問題都可以輕易靈活的解決 與MyISAM存儲引擎相比,MyISAM存儲引擎是自己記錄了表中數據的條數,但…

Day07_網絡編程20250721_大項目

基本代碼&#xff1a;搭建服務器客戶端&#xff0c;要求服務器使用 epoll 模型客戶端使用多線程服務器打開數據庫&#xff0c;表單格式如下name text primary key pswd text not null客戶端做一個簡單的界面&#xff1a;1&#xff1a;注冊2&#xff1a;登錄無論注冊還是登錄&am…

20250721

P5357 【模板】AC 自動機 - 洛谷 主要是構建fail樹 /* 我們可以知道的是&#xff0c;當訪問一個點x時&#xff0c;接下來需要跳轉其fail[x]&#xff0c;以此類推&#xff0c;如果在某個fail[x]上出現了一個字符串&#xff0c;那么相應的統計次數應該加1&#xff0c;然后當訪…

【INT四則優先算式】2022-9-22

緣由ccf201903-2二十四點我用暴力破解做的&#xff0c;但是兩個程序一個拿到了滿分&#xff0c;一個拿到了50分&#xff0c;看了很長時間也沒看出問題在哪里&#xff0c;希望有英雄慧眼幫我看一下-編程語言-CSDN問答 void INT四則優先算式() {//緣由https://ask.csdn.net/ques…

本地k8s集群的搭建

windows機器&#xff0c;考慮如果使用云服務器&#xff0c;每年的開銷還是太大&#xff0c;不值得&#xff0c;自己只是做demo&#xff0c;了解各種配置和使用即可&#xff0c;使用VMware的虛擬機來搭建k8s集群 使用docker安裝rancher和k8s yum -y install chronycat > /et…

B樹、B+樹的區別及MySQL為何選擇B+樹

B樹與B樹 B樹和B樹都是自平衡的多路搜索樹&#xff0c;廣泛應用于數據庫和文件系統中&#xff0c;用于高效管理大量數據。它們的設計目標是在磁盤存儲環境下減少I/O操作次數&#xff0c;提高數據訪問效率。下面我將逐步解釋兩者的定義、特性、比較以及應用場景&#xff0c;確保…

Unity之可視化編程VisualScripting快速入門

文章目錄 前言 腳本機和狀態機 腳本圖ScriptGraph 腳本圖 子圖 自定義事件 狀態圖StateGraph 狀態圖 Start狀態 創建新狀態 過渡連接 常用功能 射線檢測 補間動畫 按鈕點擊 前言 可視化腳本使您無需編寫代碼即可為游戲或應用程序創建邏輯。可視化腳本使用基于節點的可視化圖形…

2025三掌柜贈書活動第二十五期 網絡安全應急響應實戰

目錄 前言 網絡安全的重要性 關于《網絡安全應急響應實戰》 編輯推薦 內容簡介 作者簡介 圖書目錄 《網絡安全應急響應實戰》全書速覽 結束語 前言 在當今數字化時代&#xff0c;網絡安全已經成為企業和個人都無法忽視的重要問題。隨著網絡技術的飛速發展&#xff0c;…