使用createElement创建的元素拖拽时Draggable返回null问题
问题原因及解决方案
核心问题
- 动态元素未绑定拖拽事件:页面加载时你通过
document.querySelectorAll("#Data")获取了所有初始存在的元素并绑定了拖拽事件,但后续用createElement创建的新元素不在这个集合里,没有dragstart事件监听,拖拽时DraggedItem无法被赋值,drop时就返回null。 - 重复ID违反HTML规范:你给每个新创建的元素都设置
id="Data",但HTML中ID必须唯一,这会导致选择器行为异常,后续用#Data选元素只会拿到第一个匹配项。
修复代码
把绑定拖拽事件的逻辑抽成独立函数,让初始元素和新创建的元素都能复用这套逻辑,同时去掉重复ID:
window.addEventListener("load", ()=>{ const Drop = document.querySelectorAll("#Drop") const AddBug = document.getElementById("AddBug") let DraggedItem = null // 抽离绑定拖拽事件的通用函数 function bindDragEvents(item) { item.addEventListener("dragstart", () =>{ console.log("DragStart") DraggedItem = item console.log(DraggedItem) setTimeout(()=>{ item.style.display = "none" },0) }) item.addEventListener("dragend", ()=>{ console.log("dragend") setTimeout(()=>{ DraggedItem.style.display = "block" DraggedItem = null },0) }) } // 给页面初始存在的元素绑定拖拽事件 document.querySelectorAll(".Data").forEach(item => { bindDragEvents(item) }) AddBug.addEventListener("click", ()=>{ const BugInput = document.getElementById("BugInput").value const Wrapper = document.getElementById("Wrapper") const NewSpan = document.createElement("span") NewSpan.classList.add("Data") // 仅添加class,避免重复ID NewSpan.setAttribute("draggable", "true") NewSpan.innerText = BugInput Wrapper.append(NewSpan) // 给新创建的元素绑定拖拽事件 bindDragEvents(NewSpan) }) // 一次性给所有drop容器绑定事件,避免重复绑定 Drop.forEach(list => { list.addEventListener( "dragover", ( e )=>{ e.preventDefault() }) list.addEventListener( "dragenter", ( e )=>{ e.preventDefault() }) list.addEventListener( "drop", ()=>{ if(DraggedItem) { // 增加判断,防止null时出错 list.append(DraggedItem) } }) }) })
额外优化说明
- 原代码中每个拖拽元素都重复绑定了drop容器的事件,会导致同一个drop容器触发多次drop事件,现在改为一次性绑定更高效。
- 在drop事件中增加
if(DraggedItem)判断,避免意外情况引发报错。
内容的提问来源于stack exchange,提问作者Koffivi V. Woglo
相关产品推荐
相关产品推荐

