React实现从菜单拖拽元素到指定区域并在区内拖动的问题
Solution: Implement Drag-and-Drop Copy + Boundary Restriction with react-rnd
Hey there, let's tackle this drag-and-drop problem you're facing with react-rnd! From what I've gathered, your core requirements are:
- Drag elements from a menu to a target area while keeping the original element in the menu
- Ensure the cloned element can only move within the target area (no lingering between the menu and target)
Here's a step-by-step implementation based on your existing code:
1. Add State & Refs for Tracking
First, we need state to manage the cloned elements in the target area, plus refs to track drag offsets and the target container's dimensions:
import React, { useState, useRef } from "react"; import "./styles.css"; import { Rnd } from "react-rnd"; const elementStyle = { display: "flex", alignItems: "center", justifyContent: "center", border: "solid 1px #ddd", background: "#f0f0f0", position: "absolute" }; export default function App() { // Track all cloned elements in the target area const [targetElements, setTargetElements] = useState([]); // Store mouse offset relative to the dragged element's top-left corner const dragOffsetRef = useRef({ x: 0, y: 0 }); // Reference to the target container to get its position/size const targetContainerRef = useRef(null);
2. Implement Drag Copy Logic
Add handlers to the menu's Rnd component to clone elements when the drag ends inside the target area:
const handleDragStart = (e, dragData) => { // Calculate where the mouse is relative to the element's origin dragOffsetRef.current = { x: e.clientX - dragData.x, y: e.clientY - dragData.y }; }; const handleDragStop = (e) => { const targetRect = targetContainerRef.current.getBoundingClientRect(); // Check if the mouse was released inside the target container const isDropInTarget = e.clientX >= targetRect.left && e.clientX <= targetRect.right && e.clientY >= targetRect.top && e.clientY <= targetRect.bottom; if (isDropInTarget) { // Calculate the element's position relative to the target container const relativeX = e.clientX - targetRect.left - dragOffsetRef.current.x; const relativeY = e.clientY - targetRect.top - dragOffsetRef.current.y; // Add a new cloned element to the target area setTargetElements(prev => [...prev, { id: Date.now(), x: relativeX, y: relativeY }]); } };
3. Render Menu & Target Area
Update the JSX to render the menu (with the original element) and target area (with cloned, bounded elements):
return ( <div className="App"> {/* Menu Area - Original element stays here, triggers drag copy */} <div style={{ height: 150, border: "1px solid #000", position: "relative" }}> <Rnd style={elementStyle} handle=".drag-handle" default={{ x: 0, y: 0, width: 100, height: 50 }} draggableProps={{ allowAnyClick: true }} onDragStart={handleDragStart} onDragStop={handleDragStop} > <div className="drag-handle">Drag Me</div> </Rnd> </div> {/* Target Area - Cloned elements are locked here */} <div ref={targetContainerRef} style={{ height: 300, border: "1px solid #000", position: "relative", marginTop: 20 }} > {targetElements.map(element => ( <Rnd key={element.id} style={elementStyle} handle=".drag-handle" bounds="parent" // Forces element to stay within the target container position={{ x: element.x, y: element.y }} default={{ width: 100, height: 50 }} draggableProps={{ allowAnyClick: true }} > <div className="drag-handle">Cloned Element</div> </Rnd> ))} </div> </div> ); }
Key Details to Note
- Drag Copy: We don't move the original element—instead, we clone it when the drag ends inside the target area. The original stays in the menu.
- Boundary Lock: Setting
bounds="parent"on the target area'sRndcomponents ensures they can never be dragged outside the target container. - Position Accuracy: We calculate the mouse offset during drag start to make sure the cloned element appears exactly where you release the mouse.
This setup will match the behavior you're aiming for!
内容的提问来源于stack exchange,提问作者Hung Vu
相关产品推荐
相关产品推荐

