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

原生JavaScript实现不同待办列表间列表项拖拽移动的技术问题

Fixing Cross-List Drag-and-Drop for Your Todo App

Hey there! Let's figure out why your current drag-and-drop only works partially and get you set up for free cross-list item movement with vanilla JavaScript. Here's what's going wrong and how to fix it:

Key Issues in Your Current Code

  • You're only attaching drag events to one list (let list = document.querySelector('.mylist')), so other lists won't handle drag/drop actions.
  • Your isLiItem function restricts dragging to only checked items—remove that restriction if you want free movement.
  • The onDragDrop function hardcodes inserting into the first list (list.insertBefore(...)) instead of the list where the drop happens.
  • Your onDragEnd selector is broken ('.mylist .checked .unchecked' won't target any items correctly).

Step-by-Step Fixes

1. Update the Drag Event Logic

First, we'll refactor the code to handle all .mylist elements, not just the first one. We'll also remove the checked-item restriction (you can add it back later if needed by adjusting the isLiItem check).

2. Modify HTML to Include Multiple Lists

We'll add another todo list to demonstrate cross-list functionality.

3. Fix the addItem Function

Since you referenced addItem(this) in your form, we'll add a simple implementation for that too.

Complete Working Code

HTML

<div id="tasks">
  <details>
    <summary>Tasks List 1</summary>
    <form class="additem" onsubmit="addItem(this, 'tasks_list'); return false;">
      <input type="text" placeholder="Enter new task">
      <input type="submit" value="Add New Task">
    </form>
    <ul class="mylist" id="tasks_list" draggable="false"></ul>
  </details>

  <details>
    <summary>Tasks List 2</summary>
    <form class="additem" onsubmit="addItem(this, 'tasks_list_2'); return false;">
      <input type="text" placeholder="Enter new task">
      <input type="submit" value="Add New Task">
    </form>
    <ul class="mylist" id="tasks_list_2" draggable="false"></ul>
  </details>
</div>

<style>
/* Add some basic styling to see drag states */
.mylist { list-style: none; padding: 0; margin: 10px 0; }
.mylist li { padding: 8px; border: 1px solid #eee; margin: 4px 0; cursor: grab; }
.mylist li.checked { text-decoration: line-through; opacity: 0.7; }
.on-drag-start { opacity: 0.5; cursor: grabbing; }
.on-drag-enter { border-top: 2px solid #2196F3; }
</style>

JavaScript

let draggedItem;

// Updated: Allow any list item to be dragged (remove .checked check if you want free movement)
function isLiItem(event) {
  return event.target && event.target.tagName === 'LI';
}

function onDragStart(event) {
  if (isLiItem(event)) {
    event.target.classList.add('on-drag-start');
    draggedItem = event.target;
    event.dataTransfer.effectAllowed = 'move';
    event.dataTransfer.setData('text/html', event.target.innerHTML);
  }
}

function onDragEnter(event) {
  if (isLiItem(event)) {
    event.target.classList.add('on-drag-enter');
  }
}

function onDragLeave(event) {
  if (isLiItem(event)) {
    event.stopPropagation();
    event.target.classList.remove('on-drag-enter');
  }
}

function onDragOver(event) {
  // Allow dropping on the list itself too, not just list items
  if (event.target.classList.contains('mylist') || isLiItem(event)) {
    event.preventDefault();
    event.dataTransfer.dropEffect = 'move';
  }
}

function onDragDrop(event) {
  event.preventDefault();
  
  // Get the target list (either the list itself or the parent of the list item)
  const targetList = event.target.classList.contains('mylist') 
    ? event.target 
    : event.target.closest('.mylist');

  if (draggedItem && targetList) {
    // Insert before the target item if dropping on an item, else append to the list
    if (isLiItem(event)) {
      targetList.insertBefore(draggedItem, event.target);
    } else {
      targetList.appendChild(draggedItem);
    }
    
    draggedItem.classList.remove('on-drag-start');
    // Clear all drag-enter classes
    document.querySelectorAll('.on-drag-enter').forEach(item => item.classList.remove('on-drag-enter'));
  }
}

function onDragEnd(event) {
  draggedItem?.classList.remove('on-drag-start');
  document.querySelectorAll('.on-drag-enter').forEach(item => item.classList.remove('on-drag-enter'));
}

// Attach events to ALL .mylist elements
document.querySelectorAll('.mylist').forEach(list => {
  list.addEventListener('dragstart', onDragStart);
  list.addEventListener('dragover', onDragOver);
  list.addEventListener('dragenter', onDragEnter);
  list.addEventListener('dragleave', onDragLeave);
  list.addEventListener('drop', onDragDrop);
  list.addEventListener('dragend', onDragEnd);
});

// Implement the addItem function to add tasks to lists
function addItem(form, listId) {
  const input = form.querySelector('input[type="text"]');
  const taskText = input.value.trim();
  
  if (taskText) {
    const li = document.createElement('li');
    li.textContent = taskText;
    li.draggable = true; // Make sure new items are draggable
    
    // Add toggle for checked state (optional, if you want that functionality)
    li.addEventListener('click', () => li.classList.toggle('checked'));
    
    document.getElementById(listId).appendChild(li);
    input.value = '';
  }
}

What Changed?

  • Multiple List Support: We use document.querySelectorAll('.mylist') to attach events to every todo list.
  • Flexible Dropping: You can now drop items directly onto a list (not just between items) or between existing items.
  • Free Drag: Removed the .checked restriction in isLiItem—if you want to only allow checked items to be dragged, just change the function back to return event.target && event.target.classList.contains("checked");.
  • Fixed Drag Cleanup: onDragEnd now properly clears all drag state classes from every item.
  • Working Add Item: The addItem function creates draggable list items and adds them to the correct list.

Now you can drag any item between the two lists freely! Test it out by adding tasks to both lists and dragging items back and forth.

内容的提问来源于stack exchange,提问作者Исмет Брахимбашев

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 22:17:44