能否用jQuery UI resizable/draggable实现拖拽绘制式创建新DOM元素?
Got it, let's build that intuitive drag-to-create workflow you're after—replacing the click-to-generate behavior with a drag-to-draw interaction for your resizable/draggable divs. Below is a complete, vanilla JS implementation you can drop into your project (or adapt if you're using a library like jQuery UI for existing drag/resize logic):
Step 1: Basic HTML Structure
First, set up your canvas container where users will draw divs:
<div id="canvas-container"> <!-- Dynamically generated divs will live here --> </div>
Step 2: CSS for Styling & Interaction
Add styles to turn the container into a drawing surface, and style the draggable/resizable divs (including a resize handle):
#canvas-container { width: 100vw; height: 100vh; position: relative; background-color: #f5f5f5; cursor: crosshair; /* Visual cue for drawing mode */ } .draggable-resizable { position: absolute; border: 2px solid #2196F3; background-color: rgba(33, 150, 243, 0.1); cursor: move; } .resize-handle { position: absolute; width: 15px; height: 15px; background-color: #2196F3; bottom: 0; right: 0; cursor: se-resize; }
Step 3: JavaScript Logic for Drag-to-Draw & Interaction
This handles the drawing workflow, plus adds drag and resize functionality to finished divs:
const canvas = document.getElementById('canvas-container'); let isDrawing = false; let tempDiv = null; let startX, startY; // Start drawing on mouse down canvas.addEventListener('mousedown', (e) => { isDrawing = true; startX = e.clientX; startY = e.clientY; // Create temporary div for drawing preview tempDiv = document.createElement('div'); tempDiv.classList.add('draggable-resizable'); tempDiv.style.left = `${startX}px`; tempDiv.style.top = `${startY}px`; tempDiv.style.width = '0px'; tempDiv.style.height = '0px'; // Add resize handle (we'll make it functional after creation) const resizeHandle = document.createElement('div'); resizeHandle.classList.add('resize-handle'); tempDiv.appendChild(resizeHandle); canvas.appendChild(tempDiv); }); // Update div size during mouse move canvas.addEventListener('mousemove', (e) => { if (!isDrawing || !tempDiv) return; // Calculate dimensions (handle left/up drags with min values) const width = Math.abs(e.clientX - startX); const height = Math.abs(e.clientY - startY); const left = Math.min(e.clientX, startX); const top = Math.min(e.clientY, startY); // Update temp div position and size tempDiv.style.left = `${left}px`; tempDiv.style.top = `${top}px`; tempDiv.style.width = `${width}px`; tempDiv.style.height = `${height}px`; }); // Finish drawing on mouse up canvas.addEventListener('mouseup', () => { if (!isDrawing || !tempDiv) return; isDrawing = false; // Skip tiny accidental divs (adjust threshold as needed) const width = parseInt(tempDiv.style.width); const height = parseInt(tempDiv.style.height); if (width < 10 || height < 10) { tempDiv.remove(); return; } // Add drag and resize functionality to the finished div makeDraggable(tempDiv); makeResizable(tempDiv); tempDiv = null; }); // Clean up if mouse leaves canvas mid-draw canvas.addEventListener('mouseleave', () => { if (isDrawing && tempDiv) { tempDiv.remove(); isDrawing = false; tempDiv = null; } }); // Helper: Make a div draggable function makeDraggable(element) { let isDragging = false; let offsetX, offsetY; element.addEventListener('mousedown', (e) => { if (e.target.classList.contains('resize-handle')) return; // Ignore resize handle for drag isDragging = true; offsetX = e.clientX - parseInt(element.style.left); offsetY = e.clientY - parseInt(element.style.top); element.style.zIndex = 100; // Bring to front while dragging }); document.addEventListener('mousemove', (e) => { if (!isDragging) return; element.style.left = `${e.clientX - offsetX}px`; element.style.top = `${e.clientY - offsetY}px`; }); document.addEventListener('mouseup', () => { if (isDragging) { isDragging = false; element.style.zIndex = 1; // Reset z-index } }); } // Helper: Make a div resizable via its handle function makeResizable(element) { const handle = element.querySelector('.resize-handle'); let isResizing = false; let startWidth, startHeight, offsetX, offsetY; handle.addEventListener('mousedown', (e) => { isResizing = true; startWidth = parseInt(element.style.width); startHeight = parseInt(element.style.height); offsetX = e.clientX; offsetY = e.clientY; element.style.zIndex = 100; // Bring to front while resizing e.stopPropagation(); // Prevent triggering drag }); document.addEventListener('mousemove', (e) => { if (!isResizing) return; const newWidth = startWidth + (e.clientX - offsetX); const newHeight = startHeight + (e.clientY - offsetY); // Enforce minimum size element.style.width = `${Math.max(newWidth, 10)}px`; element.style.height = `${Math.max(newHeight, 10)}px`; }); document.addEventListener('mouseup', () => { if (isResizing) { isResizing = false; element.style.zIndex = 1; // Reset z-index } }); }
Key Details Explained
- Drag-to-Draw Flow: We create a temporary div on
mousedown, update its size/position in real-time duringmousemove, and finalize it onmouseup. - Negative Coordinate Handling: When users drag left or up from the starting point, we use
Math.minto keep the div positioned correctly. - Minimum Size Check: Prevents tiny, accidental divs from cluttering the canvas (adjust the threshold in the
mouseuphandler as needed). - Drag/Resize Isolation: The resize handle doesn't trigger drag events thanks to
e.stopPropagation(), and we adjust z-index to keep the active element on top.
If you're already using a library like jQuery UI or interact.js for drag/resize, you can replace the makeDraggable and makeResizable helpers with the library's methods—this vanilla implementation is just a self-contained example.
内容的提问来源于stack exchange,提问作者dom_ahdigital

