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

Kanban看板任务添加异常:点击列按钮无法在对应列新增任务

Kanban看板添加任务问题排查与修复

问题现象

开发简易Kanban看板时,点击每列底部的按钮,本该在对应列的ul.tasks中添加新任务,但实际点击任意按钮都只会向第一列添加任务;改用querySelectorAll选择所有ul.tasks后,又仅能向最后一列添加任务。

错误原因分析

  1. HTML重复ID问题:第二、第三列的按钮ID都是btn,ID在DOM中必须唯一,这会导致后续元素选择出现不可预期的问题。
  2. 目标任务列表定位错误:
    • 用document.querySelector(".tasks")只会获取页面中第一个匹配的ul元素,所以所有按钮点击都往第一列添加任务。
    • 若改用querySelectorAll,如果循环绑定事件时没处理好闭包,会导致所有事件最终指向最后一个ul元素。
  3. 事件绑定未关联对应列:原代码中点击事件没有和按钮所在列的任务列表建立关联,始终操作同一个固定的tasks元素。

修复方案

  1. 修正HTML中重复的按钮ID,保证每个ID唯一(或直接依赖class选择按钮,无需ID)。
  2. 在按钮点击事件中,通过父元素定位找到当前按钮所在列的ul.tasks:利用btn.parentElement.querySelector(".tasks")获取当前row下的任务列表。
  3. 修改addContent函数,让它接收目标任务列表元素作为参数,动态添加任务到对应位置。

修复后的完整代码

HTML代码

<h1>Kanban Board</h1>
<div class="container">
  <div class="row">
    <h2>Not Started</h2>
    <ul class="tasks">
    </ul>
    <button class="btn" id="btn1">+ Add(1)</button>
  </div>
  <div class="row">
    <h2>In Progress</h2>
    <ul class="tasks">
    </ul>
    <button class="btn" id="btn2">+ Add(2)</button>
  </div>
  <div class="row">
    <h2>Completed</h2>
    <ul class="tasks">
    </ul>
    <button class="btn" id="btn3">+ Add(3)</button>
  </div>
</div>

CSS代码(无需修改)

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

html {
    font-size: 62.5%;
}

body {
    font-family: "Roboto", sans-serif;
    background-color: #009578;
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    min-height: 100vh;
    gap: 6rem;
}

h1 {
    font-size: 5rem;
}

h2 {
    font-size: 3.5rem;
    font-weight: normal;
    user-select: none;
}

.container {
    display: flex;
    align-items: center;
    justify-content: space-evenly;
    flex-wrap: wrap;
    gap: 5rem;
    width: 80%;
}

.row,
.tasks {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.input-container {
    padding: 1rem;
    background-color: #fff;
    border-radius: 4px;
    display: flex;
    align-items: center;
    gap: 1rem;
    box-shadow: 0 2px 4px rgb(0 0 0 / 20%);
}

.field {
    font-size: 1.8rem;
    border-radius: 0.4rem;
    outline: 0;
    border: 0;
}

.icon {
    height: 2rem;
    color: black;
    cursor: pointer;
}

.edit {
    color: #002d24;
}

.remove {
    color: red;
}

.btn {
    padding: 1rem;
    font-size: 1.8rem;
    background-color: #00866d;
    color: #fff;
    border: 0;
    border-radius: 4px;
    cursor: pointer;
    box-shadow: 0 2px 4px rgb(0 0 0 / 20%);
}

.btn:hover {
    background-color: #006854;
}

JavaScript代码

const btns = document.querySelectorAll(".btn");

// 接收目标任务列表元素作为参数
function addContent(targetTasks) {
    const newElement = document.createElement("li");
    newElement.className = "input-container";

    const content = `<input type="text" class="field">
  
    <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
    class="w-6 h-6 edit icon">
    <path stroke-linecap="round" stroke-linejoin="round"
    d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L6.832 19.82a4.5 4.5 0 01-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 011.13-1.897L16.863 4.487zm0 0L19.5 7.125" />
    </svg>
  
    <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
    class="w-6 h-6 remove icon">
    <path stroke-linecap="round" stroke-linejoin="round"
    d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" />
    </svg>
    `;

    newElement.innerHTML = content;
    targetTasks.appendChild(newElement);
}

// 绑定事件时,获取当前按钮所在列的任务列表
btns.forEach((btn) => {
    btn.addEventListener("click", () => {
        // 找到当前按钮所在row下的tasks列表
        const targetTasks = btn.parentElement.querySelector(".tasks");
        addContent(targetTasks);
    });
});

额外优化点

  • 移除了原代码中冗余的input创建逻辑(因为innerHTML里已经包含了input)。
  • 去掉了input的重复IDinput,避免多个任务项出现重复ID的问题。

内容的提问来源于stack exchange,提问作者Mohammed-Abol-Fotouh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 21:15:06