工作事项管理小工具——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>

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

相关推荐
怕浪猫1 分钟前
React从入门到出门 第五章 React Router 配置与原理初探
前端·javascript·react.js
jinmo_C++1 分钟前
从零开始学前端 · HTML 基础篇(一):认识 HTML 与页面结构
前端·html·状态模式
鹏多多7 分钟前
前端2025年终总结:借着AI做大做强再创辉煌
前端·javascript
小Tomkk16 分钟前
⭐️ StarRocks Web 使用介绍与实战指南
前端·ffmpeg
不一样的少年_20 分钟前
产品催: 1 天优化 Vue 官网 SEO?我用这个插件半天搞定(不重构 Nuxt)
前端·javascript·vue.js
-dcr22 分钟前
50.智能体
前端·javascript·人工智能·ai·easyui
行者9631 分钟前
Flutter跨平台开发适配OpenHarmony:进度条组件的深度实践
开发语言·前端·flutter·harmonyos·鸿蒙
云和数据.ChenGuang32 分钟前
Uvicorn 是 **Python 生态中用于运行异步 Web 应用的 ASGI 服务器**
服务器·前端·人工智能·python·机器学习
IT_陈寒34 分钟前
SpringBoot 3.0实战:这5个新特性让你的开发效率提升50%
前端·人工智能·后端
winfredzhang40 分钟前
从零构建:基于 Node.js 的全栈视频资料管理系统开发实录
css·node.js·html·音视频·js·收藏,搜索,缩略图