JavaScript拖拽交换元素功能实现故障排查求助
拖拽元素互换功能修复方案
原代码核心问题
- 拖拽触发
drop事件时,e.target可能指向内部子元素(如<i>图标),导致无法获取正确的data-id,甚至引发dataTransfer相关错误 - 采用克隆元素替换的方式会丢失原元素的事件绑定,且位置交换逻辑存在偏差
- 重复遍历可拖拽元素,造成冗余操作
修复后的完整代码
HTML
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> <div id="container"> <div class="draggable" data-id="drag0"><i class="material-icons">drag_indicator</i>Draggable 0</div> <div class="draggable" data-id="drag1"><i class="material-icons">drag_indicator</i>Draggable 1</div> <div class="draggable" data-id="drag2"><i class="material-icons">drag_indicator</i>Draggable 2</div> <div class="draggable" data-id="drag3"><i class="material-icons">drag_indicator</i>Draggable 3</div> </div>
CSS
#container { width: 200px; height: auto; position: absolute; left: 50%; top: 50%; background: dodgerblue; color: #fff; transform: translate(-50%, -50%); border: 1px solid #000; } .draggable { display: flex; justify-content: start; align-items: center; border: 1px solid #fff; margin: 2px; padding: .5em; text-align: center; cursor: grab; } .draggable i { margin-right: 25px; }
JavaScript
const log = console.log.bind(console); const $ = document.getElementById.bind(document); function drop(e) { e.preventDefault(); // 定位到真正的可拖拽父元素,避免子元素触发的错误 const targetEl = e.target.closest('.draggable'); if (!targetEl) return; const dragId = e.dataTransfer.getData("text/plain"); const dragEl = document.querySelector(`[data-id="${dragId}"]`); // 排除无效或自身拖拽的情况 if (!dragEl || dragEl === targetEl) return; const container = $("container"); const siblings = [...container.children]; const dragIndex = siblings.indexOf(dragEl); const targetIndex = siblings.indexOf(targetEl); // 根据位置关系交换元素 if (dragIndex < targetIndex) { container.insertBefore(dragEl, targetEl.nextSibling); } else { container.insertBefore(dragEl, targetEl); } } // 统一初始化可拖拽元素 document.querySelectorAll(".draggable").forEach(el => { el.draggable = true; el.addEventListener("dragover", e => e.preventDefault()); el.addEventListener("dragstart", e => { // 用currentTarget确保获取绑定事件的元素,而非内部子元素 e.dataTransfer.setData("text/plain", e.currentTarget.dataset.id); }); el.addEventListener("drop", drop); });
关键修复说明
- 精准定位目标元素:通过
closest('.draggable')获取触发事件的最外层可拖拽元素,彻底解决子元素触发导致的ID获取错误 - 简化交换逻辑:直接使用
insertBefore交换两个元素的DOM位置,无需克隆,保留原元素的事件绑定 - 事件源修正:
dragstart事件中使用e.currentTarget代替e.target,确保获取的是绑定事件的.draggable元素 - 边界校验:增加元素存在性、自身拖拽的判断,避免无效操作引发的异常
- 代码优化:合并遍历操作,减少冗余DOM查询
内容的提问来源于stack exchange,提问作者TK421
相关产品推荐
相关产品推荐

