You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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按钮会:

  1. 清空旧列表并生成新的随机排列元素
  2. 自动绑定拖拽事件
  3. 拖拽功能恢复到初始状态,正常工作

内容的提问来源于stack exchange,提问作者lukas95

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 04:37:32