本文将介绍如何使用 HTML、CSS 和 JavaScript 创建一个交互式任务看板系统。该系统支持拖拽任务、添加新任务以及动态创建列,适用于任务管理和团队协作场景。
效果演示
页面结构
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}')"