这是为您生成的“记事本”交互式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 函数中找到并修改或删除它们,以替换为您自己的初始任务。