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

学习JavaScript开发Kanban看板:拖拽功能实现求助及代码优化

解决Kanban看板跨容器拖拽问题及代码优化建议

下面是修复拖拽功能后的完整代码,同时附带代码优化的细节说明:

修改后的完整代码

JavaScript

const button = document.getElementById("dataEntryButton");
const boxDataContainer = document.getElementById("boxDataContainer");
const boxDataContainer1 = document.getElementById("boxDataContainer1");
const containerDataEntry = document.getElementById("containerDataEntry");

const createTable = (data) => {
  const div = document.createElement("div");
  const text = document.createElement("h1");
  const deleteTable = document.createElement("button");

  // 开启元素拖拽功能
  div.draggable = true;
  div.classList.add("draggable-item");

  text.innerText = data;
  deleteTable.innerText = "Delete Table";

  // 修复删除逻辑:直接移除当前元素,不再绑定固定容器
  deleteTable.addEventListener("click", () => {
    div.remove();
  });

  // 拖拽开始:存储元素ID,添加视觉反馈
  div.addEventListener("dragstart", (e) => {
    e.dataTransfer.setData("text/plain", div.id);
    div.style.opacity = "0.5";
  });

  // 拖拽结束:恢复元素状态
  div.addEventListener("dragend", () => {
    div.style.opacity = "1";
  });

  // 给每个拖拽元素分配唯一ID
  div.id = `draggable-${Date.now()}`;

  div.appendChild(text);
  div.appendChild(deleteTable);

  return div;
};

// 统一设置容器的拖拽接收逻辑,避免重复代码
const setupDropArea = (container) => {
  // 允许放置必须阻止默认行为
  container.addEventListener("dragover", (e) => {
    e.preventDefault();
    container.classList.add("drag-over");
  });

  // 拖拽离开容器时移除高亮
  container.addEventListener("dragleave", () => {
    container.classList.remove("drag-over");
  });

  // 处理放置动作
  container.addEventListener("drop", (e) => {
    e.preventDefault();
    container.classList.remove("drag-over");
    const draggedId = e.dataTransfer.getData("text/plain");
    const draggedElement = document.getElementById(draggedId);
    if (draggedElement) {
      container.appendChild(draggedElement);
    }
  });
};

// 初始化两个拖拽容器
setupDropArea(boxDataContainer);
setupDropArea(boxDataContainer1);

button.addEventListener("click", () => {
  const data = containerDataEntry.value.trim();
  if (!data) return; // 空内容不创建元素

  const table = createTable(data);
  boxDataContainer.appendChild(table);
  containerDataEntry.value = ""; // 清空输入框
});

CSS

#boxDataEntry {
  margin: 10px;
}

.dropArea {
  border: 1px solid black;
  min-height: 100px; /* 替换固定高度,避免元素溢出容器 */
  margin: 10px;
  padding: 10px;
  transition: background-color 0.2s ease;
}

/* 拖拽悬停时的容器高亮样式 */
.dropArea.drag-over {
  background-color: #f5f5f5;
  border-color: #888;
}

.draggable-item {
  background-color: #fff;
  border: 1px solid #eee;
  padding: 8px;
  margin: 8px 0;
  cursor: grab;
}

.draggable-item:active {
  cursor: grabbing;
}

.draggable-item h1 {
  font-size: 16px;
  margin: 0 0 8px 0;
}

.draggable-item button {
  padding: 4px 8px;
  border: none;
  background-color: #ff4444;
  color: white;
  cursor: pointer;
  border-radius: 4px;
}

HTML

<div id="boxDataEntry">
  <textarea id="containerDataEntry" cols="30" rows="10"></textarea>
  <button id="dataEntryButton">Enter</button>
</div>

<div id="boxDataContainer" class="dropArea"></div>
<div id="boxDataContainer1" class="dropArea"></div>

核心修改说明

  1. 拖拽功能实现

    • 给每个创建的元素添加draggable="true",并通过dragstart事件存储元素唯一ID,方便放置时定位元素。
    • 给两个容器统一绑定dragover、dragleave、drop事件:dragover阻止默认行为以允许放置,drop事件中取出拖拽元素并添加到当前容器。
    • 添加拖拽过程中的视觉反馈:元素拖拽时半透明,容器被悬停时变色。
  2. 代码优化点

    • 修复删除按钮逻辑:原代码只能删除第一个容器内的元素,现在改为直接移除当前元素,适配跨容器拖拽后的删除需求。
    • 添加输入校验:点击按钮时先判断输入内容是否为空,避免创建无效元素,同时清空输入框提升操作体验。
    • 复用拖拽逻辑:用setupDropArea函数统一处理两个容器的拖拽事件,减少重复代码。
    • 样式优化:容器改为min-height避免元素溢出,给拖拽元素和删除按钮添加样式,提升视觉体验。
    • 移除无效代码:删除原代码中无意义的makeDraggable变量。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 02:10:56