如何实现拖拽复制按钮到容器而不转移原按钮?(类Scratch拖拽开发问题)
问题修复说明
你代码中存在4个核心问题导致效果不符合预期:
- 克隆逻辑绑定到了持续触发的
dragover事件,会导致拖拽过程中不断生成冗余克隆 - 克隆元素时调用
document.getElementById(draggable)语法错误,draggable本身已是DOM对象,无需二次查询 - 所有克隆元素使用固定ID
cloneId,违反DOM ID唯一性要求 - 未监听
drop事件,拖拽完成的逻辑应该在drop触发时执行,dragover仅需做默认行为阻止即可
修正后的完整JS代码
const draggables = document.querySelectorAll('.draggable') const containers = document.querySelectorAll('.container') // 新增克隆计数器,保证所有克隆ID唯一 let cloneCount = 0 // 循环绑定拖拽元素事件 draggables.forEach(draggable => { draggable.addEventListener('dragstart', (e) => { console.log('drag start') draggable.classList.add('dragging') // 将拖拽元素ID存入传输对象,提升兼容性 e.dataTransfer.setData('text/plain', draggable.id) }) draggable.addEventListener('dragend', () => { draggable.classList.remove('dragging') }) }) containers.forEach(container => { // dragover仅阻止默认行为,允许放置 container.addEventListener('dragover', e => { e.preventDefault() }) // 新增drop事件,拖拽完成时执行克隆逻辑 container.addEventListener('drop', e => { e.preventDefault() const afterElement = getDragAfterElement(container, e.clientY) const draggable = document.querySelector('.dragging') // 直接克隆原拖拽元素 const draggableClone = draggable.cloneNode(true) // 生成唯一ID draggableClone.id = `${draggable.id}_clone_${cloneCount++}` if (afterElement == null) { container.appendChild(draggableClone) } else { container.insertBefore(draggableClone, afterElement) } }) }) // 原位置计算函数无需修改 function getDragAfterElement(container, y) { const draggableElements = [...container.querySelectorAll('.draggable:not(.dragging)')] return draggableElements.reduce((closest, child) => { const box = child.getBoundingClientRect() const offset = y - box.top - box.height / 2 if (offset < 0 && offset > closest.offset) { return { offset: offset, element: child } } else { return closest } }, { offset: Number.NEGATIVE_INFINITY }).element }
额外规范提示
你的HTML代码中存在无效标签:所有<input type="button">后多余了</button>闭合标签,input为自闭合标签,可删除冗余的闭合标签避免渲染异常。
内容的提问来源于stack exchange,提问作者Christian Chim
相关产品推荐
相关产品推荐

