JavaScript拖拽重置后功能失效问题求助
双列表拖拽重置后失效的修复方案
问题背景
开发双列表拖拽匹配Web应用时,点击Reset按钮后元素能回到随机位置,但拖拽功能完全失效。
复现步骤
- 加载页面,测试拖拽功能正常
- 在两个列表间拖拽元素
- 点击Reset按钮重置元素位置
- 再次尝试拖拽,功能无响应
问题根源
每次调用createList生成新列表时,全局的leftList和rightList数组未被清空,导致数组中堆积了大量已从DOM中移除的旧元素。后续拖拽逻辑依赖这两个数组,但实际操作的是新生成的DOM元素,两者不匹配,导致拖拽事件无法正确触发。此外,resetApp中手动移除事件、重置元素位置的逻辑完全多余,因为createList会重新生成所有DOM元素并绑定新事件。
修复代码
1. 修正createList函数
在函数开头清空全局数组,确保数组仅包含当前DOM元素:
function createList() { leftDiv.innerHTML = ''; rightDiv.innerHTML = ''; // 清空数组,避免旧元素残留 leftList.length = 0; rightList.length = 0; // ... 剩余代码保持不变 }
2. 简化resetApp函数
移除多余逻辑,直接调用createList完成重置:
function resetApp() { createList(); }
完整修复后的JavaScript代码
const grid = document.querySelector('.grid'); const leftDiv = document.querySelector('.left-side') const rightDiv = document.querySelector('.right-side'); const btn = document.querySelector('.btn'); const resetBtn = document.querySelector('.js-reset-btn') const pairs = [ {pol: 'jeden', eng: 'one'}, {pol: 'dwa', eng: 'two'}, {pol: 'trzy', eng: 'three'}, {pol: 'cztery', eng:'four'}, {pol: 'piec', eng: 'five'}, ] const leftList = []; const rightList = []; let leftElement; createList(); function createList() { leftDiv.innerHTML = ''; rightDiv.innerHTML = ''; // 清空数组,避免旧元素残留 leftList.length = 0; rightList.length = 0; const leftSide = [...pairs] .map(a => ({ value: a.pol, sort: Math.random() })) .sort((a, b) => a.sort - b.sort) .map(a => a.value) .forEach((item, index) => { leftElement = document.createElement('div'); leftElement.setAttribute('data-index', index); leftElement.setAttribute('data-left', true); leftElement.innerHTML = ` <div class="draggable left-draggable" draggable="true" data-left="true"> <p class="item-name">${item}</p> </div> `; leftDiv.appendChild(leftElement); leftList.push(leftElement); }); const rightSide = [...pairs] .map(a => ({ value: a.eng, sort: Math.random() })) .sort((a, b) => a.sort - b.sort) .map(a => a.value) .forEach((item, index) => { const rightElement = document.createElement('div'); rightElement.setAttribute('data-index', index); rightElement.setAttribute('data-right', true); rightElement.innerHTML = ` <div class="draggable right-draggable" draggable="true" data-right="true"> <p class="item-name">${item}</p> </div> `; rightDiv.appendChild(rightElement); rightList.push(rightElement); }); addEventListener(); } function addEventListener() { console.log('Adding event listeners...') document.querySelectorAll('.draggable').forEach((item, index) =>{ item.addEventListener('dragstart', dragStart); }); document.querySelectorAll('[data-index]').forEach(item => { item.addEventListener('dragenter', dragEnter); item.addEventListener('dragleave', dragLeave); item.addEventListener('dragover', dragOver); item.addEventListener('drop', dragDrop); }); } let dragOrigin; let dragStartIndex; function dragStart(e) { if(e.target.getAttribute('data-left')){ dragOrigin = 'left'; dragStartIndex = +this.closest('[data-index]').getAttribute('data-index'); } else if(e.target.getAttribute('data-right')){ dragOrigin = 'right'; dragStartIndex = +this.closest('[data-index]').getAttribute('data-index'); } } function dragEnter() {} function dragLeave() {} function dragOver(e) { e.preventDefault(); } function dragDrop(e) { if(e.target.closest('[data-right]')){ if(dragOrigin !== 'right'){ return; } else { const dragEndIndex = +this.closest('[data-index]').getAttribute('data-index'); swapItems(dragStartIndex, dragEndIndex, 'right'); } } else if(e.target.closest('[data-left]')){ if(dragOrigin !== 'left'){ return; } else { const dragEndIndex = +this.closest('[data-index]').getAttribute('data-index'); swapItems(dragStartIndex, dragEndIndex, 'left'); } } } function swapItems(fromIndex, toIndex, data) { if(data === 'right' ){ const itemOne = rightList[fromIndex].querySelector('.right-draggable'); const itemTwo = rightList[toIndex].querySelector('.right-draggable'); if(itemOne.getAttribute('data-right') && itemTwo.getAttribute('data-right')){ rightList[fromIndex].appendChild(itemTwo); rightList[toIndex].appendChild(itemOne); } } else if(data === 'left') { const itemOne = leftList[fromIndex].querySelector('.left-draggable'); const itemTwo = leftList[toIndex].querySelector('.left-draggable'); if(itemOne.getAttribute('data-left') && itemTwo.getAttribute('data-left')){ leftList[fromIndex].appendChild(itemTwo); leftList[toIndex].appendChild(itemOne); } } } btn.addEventListener('click', checkOrder); function checkOrder() { leftList.forEach((leftItem, index) => { const rightItem = rightList[index]; let leftMatch = false; let rightMatch = false; pairs.forEach((pair) => { if(leftItem.querySelector('.left-draggable').textContent.trim() === pair.pol && rightItem.querySelector('.right-draggable').textContent.trim() === pair.eng){ leftMatch = true; rightMatch = true; } }); rightItem.classList.remove('right','wrong'); leftItem.classList.remove('right','wrong'); if(!leftMatch || !rightMatch){ rightItem.classList.add('wrong'); leftItem.classList.add('wrong'); } else { rightItem.classList.add('right'); leftItem.classList.add('right'); } }); } function resetApp() { createList(); } resetBtn.addEventListener('click', resetApp );
CSS代码(无需修改)
*{ box-sizing: border-box; margin: 0; padding: 0; } .grid { display: flex; margin: 50px auto; width: 500px; justify-content: center; /* gap: 30px; */ } div[data-index] { padding: 25px; border: solid 2px #333; } .item-name { font-size: 25px; font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif; text-transform: uppercase; padding: 10px 20px; border: 2px solid #ccc; border-radius: 16px; text-align: center; cursor: pointer; } .right{ background-color: green; } .wrong{ background-color: red; }
HTML代码(无需修改)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <link rel="stylesheet" href="style.css"> </head> <body> <div class="grid"> <div class="left-side"></div> <div class="right-side"></div> </div> <button class="btn">Check Order</button> <button class="js-reset-btn">Reset</button> <script src="main.js"></script> </body> </html>
效果验证
修复完成后,点击Reset按钮会:
- 清空旧列表并生成新的随机排列元素
- 自动绑定拖拽事件
- 拖拽功能恢复到初始状态,正常工作
内容的提问来源于stack exchange,提问作者lukas95
相关产品推荐
相关产品推荐

