Angular 5 + Dragula无法实现多层内部对象拖拽问题
Hey there, let's work through this drag-and-drop issue you've been stuck on for days! I get it—getting nested divs and string array data to play nice with drag functionality can be tricky. Let's start by breaking down the core pieces you need to fix, based on your setup (red main div, black containers, blue items).
1. Add Essential Drag Attributes & Event Hooks
First, your blue item divs need to explicitly be marked as draggable, and you need to hook up the 3 key drag events: dragstart, dragover, and drop (browsers block drops by default unless you override it).
Updated HTML Snippet
<!-- Red main container --> <div class="main-container"> <!-- Black container divs --> <div class="item-container" data-container-id="container-1"> <!-- Blue draggable items --> <div class="item" draggable="true" data-item-text="First Item">First Item</div> <div class="item" draggable="true" data-item-text="Second Item">Second Item</div> </div> <div class="item-container" data-container-id="container-2"> <div class="item" draggable="true" data-item-text="Third Item">Third Item</div> </div> </div>
2. Sync Drag Actions with Your String Array Data
Since you're working with an array of objects (each holding a string array of items), you need to tie DOM drag events directly to updating this data model. Here's a TypeScript example that handles both the UI and data sync:
TypeScript Logic Example
// Your data model (match this to your actual object structure) interface Container { id: string; items: string[]; } // Initial data let containers: Container[] = [ { id: "container-1", items: ["First Item", "Second Item"] }, { id: "container-2", items: ["Third Item"] } ]; // Track the currently dragged item let activeDragItem: string | null = null; // Initialize drag event listeners function setupDragEvents() { // Handle drag start (mark item as dragging, store its value) document.addEventListener("dragstart", (e) => { const target = e.target as HTMLElement; if (target.classList.contains("item")) { activeDragItem = target.dataset.itemText || null; target.classList.add("dragging"); } }); // Clean up drag state when done document.addEventListener("dragend", (e) => { const target = e.target as HTMLElement; if (target.classList.contains("item")) { target.classList.remove("dragging"); } }); // Allow drop by preventing default browser behavior document.addEventListener("dragover", (e) => { e.preventDefault(); const container = e.target.closest(".item-container") as HTMLElement; if (container) container.classList.add("drag-over"); }); // Remove hover state when dragging leaves a container document.addEventListener("dragleave", (e) => { const container = e.target.closest(".item-container") as HTMLElement; if (container) container.classList.remove("drag-over"); }); // Handle the drop event (update data + re-render UI) document.addEventListener("drop", (e) => { e.preventDefault(); const targetContainer = e.target.closest(".item-container") as HTMLElement; if (!targetContainer || !activeDragItem) return; targetContainer.classList.remove("drag-over"); const targetContainerId = targetContainer.dataset.containerId || ""; // 1. Remove item from its original container's data containers = containers.map(container => { if (container.items.includes(activeDragItem)) { return { ...container, items: container.items.filter(i => i !== activeDragItem) }; } return container; }); // 2. Add item to the target container's data containers = containers.map(container => { if (container.id === targetContainerId) { return { ...container, items: [...container.items, activeDragItem] }; } return container; }); // 3. Re-render the UI to reflect updated data renderContainers(); }); } // Helper to re-render containers from the data model function renderContainers() { const mainContainer = document.querySelector(".main-container") as HTMLElement; mainContainer.innerHTML = ""; containers.forEach(container => { const containerDiv = document.createElement("div"); containerDiv.className = "item-container"; containerDiv.dataset.containerId = container.id; container.items.forEach(item => { const itemDiv = document.createElement("div"); itemDiv.className = "item"; itemDiv.draggable = true; itemDiv.dataset.itemText = item; itemDiv.textContent = item; containerDiv.appendChild(itemDiv); }); mainContainer.appendChild(containerDiv); }); } // Initialize everything setupDragEvents(); renderContainers();
3. Add Styling for Clear Drag Feedback
These CSS rules will make the drag experience intuitive for users:
.main-container { background-color: red; padding: 1.5rem; display: flex; gap: 1.5rem; } .item-container { background-color: black; padding: 1rem; min-width: 180px; display: flex; flex-direction: column; gap: 0.75rem; transition: border 0.2s; } .item { background-color: blue; color: white; padding: 0.75rem; cursor: grab; transition: opacity 0.2s; } .item.dragging { opacity: 0.5; cursor: grabbing; } .item-container.drag-over { border: 2px dashed white; }
4. Troubleshooting Common Hiccups
- Items won't drag: Double-check that
draggable="true"is set on every blue item, and that your event listeners are properly initialized (callsetupDragEvents()after the DOM loads!). - Drop doesn't register: Make sure you're calling
e.preventDefault()in thedragoverevent—browsers block drops by default. - Data doesn't update: Verify your
renderContainersfunction is using the latestcontainersarray to rebuild the DOM (avoid mutating the original array directly—use spread operators like in the example).
If you're hitting a specific issue (like items disappearing after drop, or visual glitches in your screenshot), share those details and we can narrow it down further!
内容的提问来源于stack exchange,提问作者Kiho

