如何将现有拖拽交换改为拖拽重排(无第三方库+Grid布局)
实现Grid布局下的拖拽重排功能
基于你现有的代码,我们可以通过直接操作DOM节点来实现拖拽重排,而非交换元素内容。以下是修改后的完整实现:
HTML
<script src="https://kit.fontawesome.com/a26f6e4ee4.js"></script> <div class="components drag-container"> </div>
CSS
.components{ display: grid; grid-template-columns: repeat(auto-fit, minmax(58px, 1fr)); align-content: baseline; gap: 2em; padding: 10px; } .component{ gap: 5px; max-width: 80px; display: flex; flex-direction: column; justify-content:center; align-items:center; padding: 10px; text-align:center; cursor: grab; transition: background-color 0.2s ease; } .component:hover{ border: 1px solid gray; } .component button{ width: 30px; height: 30px; } .draggable-box{ padding: 4px; } .draggable-box.over{ background-color: rgba(0,0,0,0.1); border-radius: 4px; } .dragging{ opacity: 0.4; cursor: grabbing; }
JavaScript
const container = document.querySelector(".drag-container"); const template = ` <div draggable="true" class="draggable-box"> <div class="component draggable" id="%id%"> <button> <i class="fa-solid fa-lightbulb"></i> </button> <span>%name%</span> </div> </div>`; let items, dragSrcEl; const fillDragContainer = function () { for (let i = 0; i < 10; i++) { let friendlyIndex = i+1; let html = template.replace("%id%", `comp_${friendlyIndex}`).replace("%name%", `Name ${friendlyIndex}`); container.insertAdjacentHTML("beforeend", html); } addEventsToElements(); } const handleDragStart = function(e) { this.classList.add('dragging'); dragSrcEl = this; e.dataTransfer.effectAllowed = 'move'; } const handleDragEnd = function(e) { this.classList.remove('dragging'); items.forEach(item => item.classList.remove('over')); } const handleDragOver = function(e) { e.preventDefault(); e.dataTransfer.dropEffect = 'move'; return false; } const handleDragEnter = function(e) { if(this !== dragSrcEl){ this.classList.add('over'); } } const handleDragLeave = function(e) { this.classList.remove('over'); } const handleDrop = function(e) { e.stopPropagation(); e.preventDefault(); if (dragSrcEl !== this) { const siblings = Array.from(container.children); const srcIndex = siblings.indexOf(dragSrcEl); const targetIndex = siblings.indexOf(this); if(srcIndex < targetIndex){ container.insertBefore(dragSrcEl, this.nextSibling); } else { container.insertBefore(dragSrcEl, this); } } this.classList.remove('over'); return false; } const addEventsToElements = function () { items = document.querySelectorAll(".draggable-box"); items.forEach(item => { item.addEventListener('dragstart', handleDragStart); item.addEventListener('dragend', handleDragEnd); item.addEventListener('dragover', handleDragOver); item.addEventListener('dragenter', handleDragEnter); item.addEventListener('dragleave', handleDragLeave); item.addEventListener('drop', handleDrop); }); } fillDragContainer();
关键修改说明
- DOM节点移动替代内容交换:在
handleDrop中通过insertBefore直接移动拖拽的DOM节点,而非交换innerHTML,确保整个元素被重排,Grid布局会自动适配新的元素顺序。 - 优化视觉反馈:新增
.dragging类标记正在拖拽的元素,.over类标记拖拽进入的目标位置,让拖拽状态更直观。 - 简化事件逻辑:移除冗余的状态变量,精简事件处理逻辑,避免状态混乱。
- 适配Grid布局:Grid布局会根据子元素顺序自动重排,只需调整DOM节点顺序即可实现流式重排效果。
内容的提问来源于stack exchange,提问作者Dr.Random
相关产品推荐
相关产品推荐

