记事本案例

wen java案例 2

这是为您生成的“记事本”交互式HTML案例,一个可直接运行的待办事项管理工具。

记事本案例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">记事本 · 简洁待办</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
        }
        body {
            background: linear-gradient(145deg, #f6f8fc 0%, #eef2f7 100%);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 16px;
            margin: 0;
        }
        .notebook {
            max-width: 560px;
            width: 100%;
            background: #ffffff;
            border-radius: 32px;
            box-shadow: 0 20px 40px -12px rgba(0, 20, 40, 0.25), 0 8px 16px -8px rgba(0, 20, 40, 0.1);
            padding: 28px 24px 32px;
            transition: all 0.2s ease;
            border: 1px solid rgba(255, 255, 255, 0.5);
            backdrop-filter: blur(2px);
        }
        .header {
            display: flex;
            align-items: center;
            gap: 10px;
            margin-bottom: 22px;
            padding-bottom: 16px;
            border-bottom: 2px solid #f0f3f8;
        }
        .header h1 {
            font-size: 1.8rem;
            font-weight: 650;
            color: #1e293b;
            letter-spacing: -0.02em;
            display: flex;
            align-items: center;
            gap: 10px;
        }
        .header h1 span {
            background: #e9eef7;
            border-radius: 40px;
            padding: 4px 12px;
            font-size: 0.9rem;
            font-weight: 500;
            color: #3b4a5f;
        }
        .header i {
            color: #4070b0;
            font-size: 28px;
        }
        /* 输入区域 */
        .editor {
            display: flex;
            flex-direction: column;
            gap: 14px;
            margin-bottom: 28px;
        }
        .input-group {
            display: flex;
            align-items: center;
            background: #f9fbfd;
            border-radius: 50px;
            border: 1.5px solid #e1e8f0;
            transition: all 0.2s;
            padding: 4px;
            box-shadow: inset 0 2px 4px rgba(0,0,0,0.02);
        }
        .input-group:focus-within {
            border-color: #3f7ac6;
            background: white;
            box-shadow: 0 0 0 3px rgba(63, 122, 198, 0.15);
        }
        .input-group input {
            flex: 1;
            border: none;
            background: transparent;
            padding: 12px 20px;
            font-size: 1rem;
            outline: none;
            color: #1e293b;
            font-weight: 450;
        }
        .input-group input::placeholder {
            color: #8896ab;
            font-weight: 350;
        }
        .btn-add {
            background: #3f7ac6;
            border: none;
            color: white;
            width: 48px;
            height: 48px;
            border-radius: 50%;
            font-size: 28px;
            font-weight: 300;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: 0.15s;
            box-shadow: 0 4px 10px rgba(63, 122, 198, 0.35);
            margin: 4px;
            line-height: 1;
        }
        .btn-add:hover {
            background: #2f62a8;
            transform: scale(0.96);
        }
        .btn-add:active {
            transform: scale(0.92);
        }
        /* 分类标签 */
        .category-tabs {
            display: flex;
            gap: 8px;
            margin-bottom: 22px;
            flex-wrap: wrap;
        }
        .cat-btn {
            background: transparent;
            border: 1.5px solid #d7e0ea;
            padding: 8px 16px;
            border-radius: 40px;
            font-size: 0.9rem;
            font-weight: 500;
            color: #41546e;
            cursor: pointer;
            transition: all 0.15s;
            flex: 1 0 auto;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 6px;
            background: #f5f8fc;
        }
        .cat-btn i {
            font-size: 16px;
        }
        .cat-btn.active {
            background: #1e293b;
            border-color: #1e293b;
            color: white;
            box-shadow: 0 6px 12px rgba(0, 0, 0, 0.08);
        }
        .cat-btn .count {
            background: rgba(0,0,0,0.08);
            padding: 2px 8px;
            border-radius: 30px;
            font-size: 0.8rem;
            font-weight: 600;
        }
        .cat-btn.active .count {
            background: rgba(255,255,255,0.25);
        }
        /* 列表区域 */
        .task-container {
            background: #ffffff;
            border-radius: 24px;
            padding: 6px 4px;
            max-height: 380px;
            overflow-y: auto;
            margin-bottom: 6px;
            scrollbar-width: thin;
            scrollbar-color: #bdc8d8 #f0f4fa;
        }
        .task-container::-webkit-scrollbar {
            width: 6px;
        }
        .task-container::-webkit-scrollbar-track {
            background: #f0f4fa;
            border-radius: 20px;
        }
        .task-container::-webkit-scrollbar-thumb {
            background: #bdc8d8;
            border-radius: 20px;
        }
        .task-item {
            display: flex;
            align-items: center;
            padding: 14px 16px;
            background: #ffffff;
            border-radius: 18px;
            margin-bottom: 8px;
            transition: all 0.15s;
            border: 1px solid transparent;
            box-shadow: 0 1px 4px rgba(0,0,0,0.02);
        }
        .task-item:hover {
            background: #f7faff;
            border-color: #dfe7f2;
        }
        .task-item.completed .task-text {
            text-decoration: line-through;
            color: #a0aebe;
        }
        .task-item.completed {
            opacity: 0.75;
        }
        .task-check {
            margin-right: 12px;
            flex-shrink: 0;
        }
        .task-check input {
            width: 22px;
            height: 22px;
            cursor: pointer;
            accent-color: #3f7ac6;
            border-radius: 6px;
        }
        .task-content {
            flex: 1;
            min-width: 0;
        }
        .task-text {
            font-size: 1.05rem;
            font-weight: 500;
            color: #1e293b;
            overflow-wrap: break-word;
            word-break: break-word;
            line-height: 1.4;
        }
        .task-meta {
            display: flex;
            align-items: center;
            gap: 8px;
            margin-top: 4px;
            flex-wrap: wrap;
        }
        .task-category {
            font-size: 0.75rem;
            background: #eef3fa;
            padding: 3px 10px;
            border-radius: 40px;
            color: #304a6e;
            font-weight: 500;
        }
        .task-date {
            font-size: 0.75rem;
            color: #7d8da4;
            display: flex;
            align-items: center;
            gap: 4px;
        }
        .task-delete {
            background: transparent;
            border: none;
            color: #b9c6d6;
            font-size: 20px;
            cursor: pointer;
            padding: 8px 8px;
            border-radius: 30px;
            transition: all 0.15s;
            margin-left: 8px;
            flex-shrink: 0;
            line-height: 1;
        }
        .task-delete:hover {
            color: #e5475c;
            background: #fdecee;
        }
        .empty-state {
            text-align: center;
            padding: 36px 20px;
            color: #9badc2;
            font-size: 0.95rem;
        }
        .empty-state i {
            font-size: 40px;
            opacity: 0.5;
            display: block;
            margin-bottom: 10px;
        }
        /* 底部统计 */
        .footer-actions {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-top: 14px;
            padding-top: 18px;
            border-top: 2px solid #f0f3f8;
            font-size: 0.9rem;
            color: #526482;
            flex-wrap: wrap;
            gap: 10px;
        }
        .stats {
            font-weight: 450;
        }
        .clear-btn {
            background: transparent;
            border: 1px solid #d9e1ec;
            padding: 8px 14px;
            border-radius: 40px;
            cursor: pointer;
            color: #526482;
            font-size: 0.85rem;
            transition: 0.15s;
            display: flex;
            align-items: center;
            gap: 6px;
            font-weight: 500;
        }
        .clear-btn:hover {
            background: #f2f6fa;
            border-color: #b9c5d8;
            color: #1f2c3d;
        }
        .clear-btn:active {
            background: #e7ecf3;
        }
        /* 模拟text icon 使用emoji或unicode */
        .icon-note { font-size: 26px; }
        /* 移动端适配 */
        @media (max-width: 480px) {
            .notebook { padding: 20px 16px; }
            .header h1 { font-size: 1.5rem; }
            .btn-add { width: 44px; height: 44px; }
            .task-item { padding: 12px; }
        }
    </style>
</head>
<body>
    <div class="notebook">
        <!-- 头部 -->
        <div class="header">
            <h1>
                <span class="icon-note">📓</span> 记事本
                <span class="badge">待办</span>
            </h1>
        </div>
        <!-- 新增待办 -->
        <div class="editor">
            <div class="input-group">
                <input type="text" id="newTaskInput" placeholder="写点什么… 按回车即可" maxlength="120" autofocus>
                <button class="btn-add" id="addTaskBtn" aria-label="添加">+</button>
            </div>
            <div class="category-tabs" id="categoryTabs">
                <button class="cat-btn active" data-cat="all">📋 全部 <span class="count" id="countAll">0</span></button>
                <button class="cat-btn" data-cat="工作">💼 工作 <span class="count" id="countWork">0</span></button>
                <button class="cat-btn" data-cat="生活">🏖️ 生活 <span class="count" id="countLife">0</span></button>
                <button class="cat-btn" data-cat="学习">📚 学习 <span class="count" id="countStudy">0</span></button>
            </div>
        </div>
        <!-- 待办列表容器 -->
        <div class="task-container" id="taskListContainer">
            <!-- 动态插入 item -->
        </div>
        <!-- 底部 统计 清空完成 -->
        <div class="footer-actions">
            <div class="stats" id="statsText">共 0 项 · 已完成 0 项</div>
            <button class="clear-btn" id="clearCompletedBtn">🧹 清理已完成</button>
        </div>
    </div>
    <script>
        (function(){
            // ----- 数据模型 -----
            let tasks = []; // { id, text, category, completed, date }
            // 当前选中的分类筛选 (all / 工作 / 生活 / 学习)
            let currentFilter = 'all';
            // DOM 元素
            const inputEl = document.getElementById('newTaskInput');
            const addBtn = document.getElementById('addTaskBtn');
            const listContainer = document.getElementById('taskListContainer');
            const statsText = document.getElementById('statsText');
            const clearCompletedBtn = document.getElementById('clearCompletedBtn');
            // 分类标签 & 计数器
            const catButtons = document.querySelectorAll('.cat-btn');
            const countAllEl = document.getElementById('countAll');
            const countWorkEl = document.getElementById('countWork');
            const countLifeEl = document.getElementById('countLife');
            const countStudyEl = document.getElementById('countStudy');
            // ----- 辅助函数 -----
            function formatDate(ts) {
                const d = new Date(ts);
                const y = d.getFullYear();
                const m = String(d.getMonth() + 1).padStart(2,'0');
                const day = String(d.getDate()).padStart(2,'0');
                return `${y}.${m}.${day}`;
            }
            // 生成ID
            function generateId() {
                return Date.now() + Math.random().toString(36).substr(2, 8);
            }
            // 获取当前分类下所有任务 (筛选)
            function getFilteredTasks() {
                if (currentFilter === 'all') return tasks;
                return tasks.filter(t => t.category === currentFilter);
            }
            // 计算分类计数
            function updateCounts() {
                const total = tasks.length;
                const work = tasks.filter(t => t.category === '工作').length;
                const life = tasks.filter(t => t.category === '生活').length;
                const study = tasks.filter(t => t.category === '学习').length;
                countAllEl.textContent = total;
                countWorkEl.textContent = work;
                countLifeEl.textContent = life;
                countStudyEl.textContent = study;
                // 更新底部统计
                const completed = tasks.filter(t => t.completed).length;
                statsText.textContent = `共 ${total} 项 · 已完成 ${completed} 项`;
            }
            // 渲染任务列表
            function renderList() {
                const filtered = getFilteredTasks();
                if (filtered.length === 0) {
                    listContainer.innerHTML = `
                        <div class="empty-state">
                            <i>🗒️</i>
                            <span>${currentFilter === 'all' ? '暂无记录,添加一条吧' : '这个分类还没有任务'}</span>
                        </div>`;
                    return;
                }
                // 排序:未完成在前,完成在后,日期最新靠前(也可不加)
                const sorted = [...filtered].sort((a,b) => {
                    if (a.completed !== b.completed) return a.completed ? 1 : -1;
                    return b.date - a.date;
                });
                let html = '';
                for (const task of sorted) {
                    const isCompletedClass = task.completed ? 'completed' : '';
                    const categoryLabel = task.category;
                    const dateStr = formatDate(task.date);
                    html += `
                        <div class="task-item ${isCompletedClass}" data-id="${task.id}">
                            <div class="task-check">
                                <input type="checkbox" ${task.completed ? 'checked' : ''} data-id="${task.id}" class="toggle-check" aria-label="切换完成状态">
                            </div>
                            <div class="task-content">
                                <div class="task-text">${escapeHtml(task.text)}</div>
                                <div class="task-meta">
                                    <span class="task-category">${categoryLabel}</span>
                                    <span class="task-date">📅 ${dateStr}</span>
                                </div>
                            </div>
                            <button class="task-delete" data-id="${task.id}" aria-label="删除任务">🗑️</button>
                        </div>
                    `;
                }
                listContainer.innerHTML = html;
                // 绑定动态事件 (checkbox change, 删除按钮)
                listContainer.querySelectorAll('.toggle-check').forEach(checkbox => {
                    checkbox.addEventListener('change', function(e) {
                        const id = this.dataset.id;
                        toggleTaskCompletion(id);
                    });
                });
                listContainer.querySelectorAll('.task-delete').forEach(btn => {
                    btn.addEventListener('click', function(e) {
                        const id = this.dataset.id;
                        deleteTask(id);
                    });
                });
            }
            // 简易转义函数(防止XSS)
            function escapeHtml(text) {
                const div = document.createElement('div');
                div.textContent = text;
                return div.innerHTML;
            }
            // ----- 核心操作 -----
            // 添加任务
            function addTask(text) {
                const trimmed = text.trim();
                if (!trimmed) {
                    alert('请输入内容');
                    return false;
                }
                // 自动选择分类(基于默认?这里简单使用默认“生活”,但更好是用户手动选择,但这里可根据tab?但更简单:选择一个分类 // 我们使用当前激活的tab来分配?但全部时默认'生活'多一些?但更合理保留为最后一个点击的tab? 我们默认选择"生活")
                // 但为了更符合记事本直觉,默认分类 = 当前tab(如果当前是工作、生活或学习则使用;如果选择“全部”,则使用“生活”)
                let defaultCategory = '生活';
                if (currentFilter !== 'all') {
                    defaultCategory = currentFilter;
                }
                const newTask = {
                    id: generateId(),
                    text: trimmed,
                    category: defaultCategory,
                    completed: false,
                    date: Date.now()
                };
                tasks.unshift(newTask);  // 新任务在前面
                inputEl.value = '';
                updateCounts();
                renderList();
                return true;
            }
            // 切换完成状态
            function toggleTaskCompletion(id) {
                const task = tasks.find(t => t.id === id);
                if (task) {
                    task.completed = !task.completed;
                    updateCounts();
                    renderList();
                }
            }
            // 删除任务
            function deleteTask(id) {
                tasks = tasks.filter(t => t.id !== id);
                updateCounts();
                renderList();
            }
            // 清空已完成
            function clearCompleted() {
                tasks = tasks.filter(t => !t.completed);
                updateCounts();
                renderList();
            }
            // 更新激活分类样式
            function setActiveCategory(cat) {
                catButtons.forEach(btn => {
                    const dataCat = btn.dataset.cat;
                    if (dataCat === cat) {
                        btn.classList.add('active');
                    } else {
                        btn.classList.remove('active');
                    }
                });
            }
            // 切换筛选
            function switchFilter(cat) {
                currentFilter = cat;
                setActiveCategory(cat);
                renderList();
            }
            // ----- 初始化事件 -----
            // 添加按钮
            addBtn.addEventListener('click', () => {
                addTask(inputEl.value);
            });
            // 回车添加
            inputEl.addEventListener('keypress', (e) => {
                if (e.key === 'Enter') {
                    e.preventDefault();
                    addTask(inputEl.value);
                }
            });
            // 分类点击
            catButtons.forEach(btn => {
                btn.addEventListener('click', (e) => {
                    const cat = btn.dataset.cat;
                    switchFilter(cat);
                });
            });
            // 清空已完成
            clearCompletedBtn.addEventListener('click', clearCompleted);
            // 预置一些示例数据(展示案例效果)
            function loadExampleData() {
                const now = Date.now();
                tasks = [
                    { id: 'ex1', text: '整理周报 & 提交', category: '工作', completed: false, date: now - 2 * 86400000 },
                    { id: 'ex2', text: '买牛奶和全麦面包', category: '生活', completed: true, date: now - 86400000 },
                    { id: 'ex3', text: '阅读《人类简史》30页', category: '学习', completed: false, date: now - 5 * 3600000 },
                    { id: 'ex4', text: '预约牙医 (下周二)', category: '生活', completed: false, date: now - 3600000 },
                    { id: 'ex5', text: '完成项目原型设计', category: '工作', completed: false, date: now - 30 * 60000 },
                ];
                // 完成的示例放第二个
                updateCounts();
                renderList();
            }
            // 启动时加载示例数据
            loadExampleData();
            setActiveCategory('all');   // 默认全部
            // 额外细节:点击分类后新增任务使用该分类
            // 已经在addTask中使用currentFilter逻辑
        })();
    </script>
</body>
</html>

核心功能与操作指南

您可以通过以下几个模块,轻松管理您的待办事项。

  • 任务添加:在顶部的输入框中输入内容,点击 “+”按钮 或按下 回车键 即可快速添加新任务,新任务会默认归类到您当前选中的分类标签下。
  • 分类管理:通过 “全部”、“工作”、“生活”、“学习” 四个标签,您可以快速筛选查看不同类别的任务,每个标签旁的数字会实时显示该类别的任务数量。
  • 任务操作:点击任务前的 复选框 可以标记任务为“已完成”,已完成的任务会显示删除线,点击任务右侧的 垃圾桶图标 可以删除该条记录。
  • 数据统计与清理:底部区域会显示“总任务数”和“已完成数”,您可以随时点击 “清理已完成” 按钮,一键移除所有已完成的任务,保持列表整洁。

优化建议: 页面中的示例数据(如“整理周报”)是用于演示的,您可以在代码的 loadExampleData 函数中找到并修改或删除它们,以替换为您自己的初始任务。

上一篇Java小案例

下一篇运营平台案例

抱歉,评论功能暂时关闭!