使用 HTML + JavaScript 实现可拖拽的任务看板系统

本文将介绍如何使用 HTML、CSS 和 JavaScript 创建一个交互式任务看板系统。该系统支持拖拽任务、添加新任务以及动态创建列,适用于任务管理和团队协作场景。

效果演示

image-20250530222903130

image-20250530222932759

image-20250530223009693

页面结构

HTML 部分主要包含三个默认的任务列(待办、进行中、已完成)和一个用于添加新列的按钮。

<div class="board" id="board">
    <div class="column" id="todo-column">
        <div class="column-title">待办</div>
        <div class="task-list" id="todo-list">
            <div class="task" draggable="true">设计登录页面UI</div>
            <div class="task" draggable="true">编写API接口文档</div>
            <div class="task" draggable="true">项目需求评审会议</div>
        </div>
        <div class="add-task" onclick="showAddTaskForm('todo-list')">添加任务</div>
    </div>
     <!-- 其他两个列 -->
    <div class="add-column" onclick="addNewColumn()">
        <div class="add-column-icon">+</div>
        <div>添加新列</div>
    </div>
</div>

核心功能实现

拖拽功能实现

完整的拖拽逻辑包括拖拽开始、结束、移动和放置操作。

首先,获取拖拽容器的元素用来绑定拖拽时间,定义一个变量用于保存当前正在被拖动的任务项

const board = document.getElementById('board');
let draggedTask = null;

拖拽开始

board.addEventListener('dragstart', function(e) {
   
    if (e.target.classList.contains('task')) {
   
        draggedTask = e.target;
        setTimeout(() => {
   
            e.target.classList.add('dragging');
        }, 0);
    }
});

拖拽过程

board.addEventListener('dragover', function(e) {
   
    e.preventDefault();
    const afterElement = getDragAfterElement(e.target.closest('.task-list'), e.clientY);
    const draggingTask = document.querySelector('.dragging');

    if (draggingTask && e.target.closest('.task-list')) {
   
        const list = e.target.closest('.task-list');
        if (afterElement) {
   
            list.insertBefore(draggingTask, afterElement);
        } else {
   
            list.appendChild(draggingTask);
        }
    }
});

拖拽结束

board.addEventListener('dragend', function(e) {
   
    if (e.target.classList.contains('task')) {
   
        e.target.classList.remove('dragging');
    }
});

获取拖拽后应该放置的位置

function getDragAfterElement(container, y) {
   
    const draggableElements = [...container.querySelectorAll('.task:not(.dragging)')];

    return draggableElements.reduce((closest, child) => {
   
        const box = child.getBoundingClientRect();
        const offset = y - box.top - box.height / 2;

        if (offset < 0 && offset > closest.offset) {
   
            return {
    offset: offset, element: child };
        } else {
   
            return closest;
        }
    }, {
    offset: Number.NEGATIVE_INFINITY }).element;
}
添加任务功能

当用户点击“添加任务”按钮时,会动态创建一个任务输入表单,替换原来的按钮,供用户输入新任务内容。

function showAddTaskForm(listId) {
   
    const list = document.getElementById(listId);
    const addButton = list.nextElementSibling;

    // 检查是否已存在表单
    if (list.querySelector('.task-form')) return;

    // 创建表单
    const form = document.createElement('div');
    form.className = 'task-form';
    form.innerHTML = `<input type="text" class="task-input" placeholder="输入任务内容..." autofocus>
        <div class="btn-group">
        <button class="btn btn-primary" onclick="addTask('${
     listId}')">
        <span>添加任务</span>
        </button>
        <button class="btn btn-outline" onclick="cancelAddTask('${
     listId}')"
出现这个错误的原因是在导入seaborn包时,无法从typing模块中导入名为'Protocol'的对象。 解决这个问题的方法有以下几种: 1. 检查你的Python版本是否符合seaborn包的要求,如果不符合,尝试更新Python版本。 2. 检查你的环境中是否安装了typing_extensions包,如果没有安装,可以使用以下命令安装:pip install typing_extensions。 3. 如果你使用的是Python 3.8版本以下的版本,你可以尝试使用typing_extensions包来代替typing模块来解决该问题。 4. 检查你的代码是否正确导入了seaborn包,并且没有其他导入错误。 5. 如果以上方法都无法解决问题,可以尝试在你的代码中使用其他的可替代包或者更新seaborn包的版本来解决该问题。 总结: 出现ImportError: cannot import name 'Protocol' from 'typing'错误的原因可能是由于Python版本不兼容、缺少typing_extensions包或者导入错误等原因造成的。可以根据具体情况尝试上述方法来解决该问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [ImportError: cannot import name ‘Literal‘ from ‘typing‘ (D:\Anaconda\envs\tensorflow\lib\typing....](https://blog.csdn.net/yuhaix/article/details/124528628)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值