工作事项管理小工具——HTML版

#工作日志与时间管理#

背景

很多人有时候日常工具繁杂,但又每件事情都要及时完成,不能出错,面对这种情况,需要一个人有良好的记忆力和良好的计划做事习惯。但往往事情多起来,光凭脑子很难记住,有些人会借助贴一些记事贴的方法来帮助自己解决问题。昨天写了一篇《工作事项管理小工具》的文章,分享了一个可在电脑上本地运行的小程序,采用Python和PyQt5编程实现。今天再来分享一个HTML版本的小程序,做的比较简单,没有Python版的编辑修改等功能,目前只实现可以对事项是否完成进行跟踪标记。

一、功能介绍

整个程序就是一个html文件,双击打开index.html文件,即可运行这个小工具。

1.1 程序界面

1.2 添加事项

直接在事项文本框中心输入,然后单击添加按钮即可完成工作事项添加。

1.3 完成事项

只要单击事项前面的复选框,事项将变成完成状态。

1.4 事项列表查看

程序默认显示全部事项列表,可通过单击"未完成"和"已完成"按钮来切换事项列表。

二、程序代码分享

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>本地待办事项</title>
    <link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
    <style>
		body { 
			width: 600px; 
			height: 400px;
			margin: 0;
		}
        .task-item { transition: all 0.3s ease; }
        .completed-task { opacity: 0.7; text-decoration: line-through; }
    </style>
</head>
<body class="bg-gray-50 min-h-screen p-4">
    <div class="max-w-2xl mx-auto bg-white rounded-lg shadow-lg p-6">
        <h1 class="text-2xl font-bold text-center mb-6">本地待办清单</h1>
        
        <div class="flex mb-4">
            <input id="taskInput" type="text" placeholder="输入新任务..." 
                   class="flex-grow p-2 border rounded-l focus:outline-none focus:ring-2 focus:ring-purple-500">
            <button id="addBtn" class="bg-purple-600 text-white px-4 py-2 rounded-r hover:bg-purple-700 transition">
                <i class="fas fa-plus mr-1"></i>添加
            </button>
        </div>

        <div class="flex space-x-2 mb-4">
            <button data-filter="all" class="filter-btn active bg-purple-600 text-white px-3 py-1 rounded">全部</button>
            <button data-filter="active" class="filter-btn bg-gray-200 px-3 py-1 rounded">未完成</button>
            <button data-filter="completed" class="filter-btn bg-gray-200 px-3 py-1 rounded">已完成</button>
        </div>

        <ul id="taskList" class="space-y-2 max-h-96 overflow-y-auto"></ul>
        
        <div id="emptyState" class="text-center py-8 text-gray-500">
            <i class="fas fa-tasks text-4xl mb-2"></i>
            <p>暂无任务,添加您的第一个任务吧!</p>
        </div>

        <div class="mt-4 flex justify-between items-center text-sm">
            <button id="clearBtn" class="text-red-500 hover:text-red-700">
                <i class="fas fa-trash-alt mr-1"></i>清除已完成
            </button>
            <span id="taskCount" class="text-gray-500">0 项任务</span>
        </div>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', function() {
            // 初始化数据
            let tasks = JSON.parse(localStorage.getItem('todo_tasks')) || [];
            let currentFilter = 'all';

            // 获取DOM元素
            const elements = {
                taskInput: document.getElementById('taskInput'),
                addBtn: document.getElementById('addBtn'),
                taskList: document.getElementById('taskList'),
                emptyState: document.getElementById('emptyState'),
                filterBtns: document.querySelectorAll('.filter-btn'),
                clearBtn: document.getElementById('clearBtn'),
                taskCount: document.getElementById('taskCount')
            };

            // 初始化应用
            function init() {
                loadTasks();
                setupEventListeners();
            }

            // 加载任务
            function loadTasks() {
                let filteredTasks = [];
                switch(currentFilter) {
                    case 'active': 
                        filteredTasks = tasks.filter(task => !task.completed); 
                        break;
                    case 'completed': 
                        filteredTasks = tasks.filter(task => task.completed); 
                        break;
                    default: 
                        filteredTasks = [...tasks];
                }

                renderTasks(filteredTasks);
                updateTaskCount();
            }

            // 渲染任务列表
            function renderTasks(tasksToRender) {
                elements.taskList.innerHTML = '';
                
                if (tasksToRender.length === 0) {
                    elements.emptyState.classList.remove('hidden');
                    return;
                }
                
                elements.emptyState.classList.add('hidden');
                
                tasksToRender.forEach(task => {
                    const li = document.createElement('li');
                    li.className = `task-item p-3 border rounded flex items-center ${task.completed ? 'completed-task bg-gray-50' : ''}`;
                    li.dataset.id = task.id;
                    
                    li.innerHTML = `
                        <input type="checkbox" class="h-5 w-5 text-purple-600 rounded mr-3" ${task.completed ? 'checked' : ''}>
                        <div class="flex-grow">
                            <div class="task-text ${task.completed ? 'line-through' : ''}">${task.text}</div>
                            <div class="text-xs text-gray-500 mt-1">
                                <i class="far fa-clock mr-1"></i>${new Date(task.createdAt).toLocaleString()}
                                ${task.completed ? `<br><i class="fas fa-check mr-1"></i>完成于: ${new Date(task.completedAt).toLocaleString()}` : ''}
                            </div>
                        </div>
                        <button class="delete-btn ml-2 text-gray-400 hover:text-red-500 transition">
                            <i class="fas fa-times"></i>
                        </button>
                    `;
                    
                    elements.taskList.appendChild(li);
                });

                // 添加事件监听
                document.querySelectorAll('.task-item input[type="checkbox"]').forEach(checkbox => {
                    checkbox.addEventListener('change', function() {
                        const taskId = this.closest('.task-item').dataset.id;
                        toggleTask(taskId);
                    });
                });

                document.querySelectorAll('.delete-btn').forEach(btn => {
                    btn.addEventListener('click', function() {
                        const taskId = this.closest('.task-item').dataset.id;
                        if (confirm('确定要删除这个任务吗?')) {
                            deleteTask(taskId);
                        }
                    });
                });
            }

            // 添加任务
            function addTask() {
                const text = elements.taskInput.value.trim();
                if (text) {
                    const newTask = {
                        id: Date.now().toString(),
                        text: text,
                        completed: false,
                        createdAt: new Date().toISOString(),
                        completedAt: null
                    };
                    
                    tasks.unshift(newTask);
                    saveTasks();
                    elements.taskInput.value = '';
                    loadTasks();
                }
            }

            // 切换任务状态
            function toggleTask(id) {
                const task = tasks.find(t => t.id === id);
                if (task) {
                    task.completed = !task.completed;
                    task.completedAt = task.completed ? new Date().toISOString() : null;
                    saveTasks();
                    loadTasks();
                }
            }

            // 删除任务
            function deleteTask(id) {
                tasks = tasks.filter(task => task.id !== id);
                saveTasks();
                loadTasks();
            }

            // 清除已完成任务
            function clearCompleted() {
                if (confirm('确定要清除所有已完成任务吗?此操作不可撤销!')) {
                    tasks = tasks.filter(task => !task.completed);
                    saveTasks();
                    loadTasks();
                }
            }

            // 设置筛选条件
            function setFilter(filter) {
                currentFilter = filter;
                elements.filterBtns.forEach(btn => {
                    btn.classList.toggle('active', btn.dataset.filter === filter);
                    btn.classList.toggle('bg-purple-600', btn.dataset.filter === filter);
                    btn.classList.toggle('text-white', btn.dataset.filter === filter);
                    btn.classList.toggle('bg-gray-200', btn.dataset.filter !== filter);
                });
                loadTasks();
            }

            // 更新任务计数
            function updateTaskCount() {
                const total = tasks.length;
                const completed = tasks.filter(t => t.completed).length;
                elements.taskCount.textContent = `${completed}/${total} 已完成`;
            }

            // 保存任务到本地存储
            function saveTasks() {
                localStorage.setItem('todo_tasks', JSON.stringify(tasks));
            }

            // 设置事件监听
            function setupEventListeners() {
                elements.addBtn.addEventListener('click', addTask);
                elements.taskInput.addEventListener('keypress', function(e) {
                    if (e.key === 'Enter') addTask();
                });
                
                elements.filterBtns.forEach(btn => {
                    btn.addEventListener('click', function() {
                        setFilter(this.dataset.filter);
                    });
                });
                
                elements.clearBtn.addEventListener('click', clearCompleted);
            }

            // 启动应用
            init();
        });
    </script>
</body>
</html>

以上就是这个小工具的全部分享,希望能够对大家有所帮助。

相关推荐
二十雨辰3 小时前
eduAi-智能体创意平台
前端·vue.js
golang学习记3 小时前
从0死磕全栈之Next.js connection() 函数详解:强制动态渲染的正确姿势(附实战案例)
前端
郝学胜-神的一滴3 小时前
Three.js光照技术详解:为3D场景注入灵魂
开发语言·前端·javascript·3d·web3·webgl
m0dw3 小时前
vue懒加载
前端·javascript·vue.js·typescript
国家不保护废物4 小时前
手写 Vue Router,揭秘路由背后的魔法!🔮
前端·vue.js
菜鸟‍4 小时前
【前端学习】仿Deepseek官网AI聊天网站React
前端·学习·react.js
小光学长4 小时前
基于Vue的保护动物信息管理系统r7zl6b88 (程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
前端·数据库·vue.js
huangql5205 小时前
截图功能技术详解:从原理到实现的完整指南
前端·html5
长空任鸟飞_阿康5 小时前
Node.js 核心模块详解:fs 模块原理与应用
前端·人工智能·ai·node.js