嵌入式开发网络引导实战:基于DHCP、TFTP与NFS的无盘启动配置详解
2026/6/8 13:12:48
作者:专注前端开发,分享JavaScript干货
更新时间:2026年4月
适合人群:学完本专栏基础内容,想通过实战巩固的开发者
待办清单(Todo App)是前端入门的经典项目,涵盖:
做完这个项目,你的JS基础就扎实了。
<!DOCTYPEhtml><htmllang="zh-CN"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>待办清单</title><style>*{margin:0;padding:0;box-sizing:border-box;}body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);min-height:100vh;padding:50px 20px;}.container{max-width:500px;margin:0 auto;background:white;border-radius:16px;padding:30px;box-shadow:0 20px 60pxrgba(0,0,0,0.3);}h1{text-align:center;color:#333;margin-bottom:30px;}.input-group{display:flex;gap:10px;margin-bottom:20px;}#todoInput{flex:1;padding:12px 16px;border:2px solid #e0e0e0;border-radius:8px;font-size:16px;outline:none;transition:border-color 0.3s;}#todoInput:focus{border-color:#667eea;}#addBtn{padding:12px 24px;background:#667eea;color:white;border:none;border-radius:8px;cursor:pointer;font-size:16px;transition:background 0.3s;}#addBtn:hover{background:#5a67d8;}.filters{display:flex;gap:10px;margin-bottom:20px;justify-content:center;}.filter-btn{padding:8px 16px;border:1px solid #e0e0e0;background:white;border-radius:20px;cursor:pointer;transition:all 0.3s;}.filter-btn.active{background:#667eea;color:white;border-color:#667eea;}.todo-list{list-style:none;}.todo-item{display:flex;align-items:center;padding:15px;border-bottom:1px solid #f0f0f0;transition:background 0.3s;}.todo-item:hover{background:#f8f9fa;}.todo-item.completed .todo-text{text-decoration:line-through;color:#999;}.todo-checkbox{width:20px;height:20px;margin-right:15px;cursor:pointer;}.todo-text{flex:1;font-size:16px;}.delete-btn{padding:6px 12px;background:#ff4757;color:white;border:none;border-radius:4px;cursor:pointer;font-size:14px;}.delete-btn:hover{background:#ff3838;}.stats{text-align:center;margin-top:20px;color:#666;}.empty-state{text-align:center;padding:40px;color:#999;}</style></head><body><divclass="container"><h1>📝 待办清单</h1><divclass="input-group"><inputtype="text"id="todoInput"placeholder="添加新的待办事项..."><buttonid="addBtn">添加</button></div><divclass="filters"><buttonclass="filter-btn active"data-filter="all">全部</button><buttonclass="filter-btn"data-filter="active">未完成</button><buttonclass="filter-btn"data-filter="completed">已完成</button></div><ulclass="todo-list"id="todoList"></ul><divclass="stats"id="stats"></div></div><scriptsrc="app.js"></script></body></html>// 待办事项管理类classTodoApp{constructor(){this.todos=JSON.parse(localStorage.getItem('todos'))||[];this.filter='all';this.todoInput=document.getElementById('todoInput');this.addBtn=document.getElementById('addBtn');this.todoList=document.getElementById('todoList');this.stats=document.getElementById('stats');this.filterBtns=document.querySelectorAll('.filter-btn');this.init();}init(){this.bindEvents();this.render();}bindEvents(){// 添加按钮点击this.addBtn.addEventListener('click',()=>this.addTodo());// 回车键添加this.todoInput.addEventListener('keypress',(e)=>{if(e.key==='Enter')this.addTodo();});// 筛选按钮this.filterBtns.forEach(btn=>{btn.addEventListener('click',(e)=>{this.filterBtns.forEach(b=>b.classList.remove('active'));e.target.classList.add('active');this.filter=e.target.dataset.filter;this.render();});});}addTodo(){consttext=this.todoInput.value.trim();if(!text){alert('请输入待办事项');return;}consttodo={id:Date.now(),text:text,completed:false,createdAt:newDate().toISOString()};this.todos.unshift(todo);this.saveTodos();this.todoInput.value='';this.render();}toggleTodo(id){consttodo=this.todos.find(t=>t.id===id);if(todo){todo.completed=!todo.completed;this.saveTodos();this.render();}}deleteTodo(id){if(confirm('确定要删除这个待办事项吗?')){this.todos=this.todos.filter(t=>t.id!==id);this.saveTodos();this.render();}}getFilteredTodos(){switch(this.filter){case'active':returnthis.todos.filter(t=>!t.completed);case'completed':returnthis.todos.filter(t=>t.completed);default:returnthis.todos;}}saveTodos(){localStorage.setItem('todos',JSON.stringify(this.todos));}render(){constfilteredTodos=this.getFilteredTodos();if(filteredTodos.length===0){this.todoList.innerHTML=`<div class="empty-state"> <p>暂无待办事项</p> </div>`;}else{this.todoList.innerHTML=filteredTodos.map(todo=>`<li class="todo-item${todo.completed?'completed':''}"> <input type="checkbox" class="todo-checkbox"${todo.completed?'checked':''}onchange="app.toggleTodo(${todo.id})"> <span class="todo-text">${this.escapeHtml(todo.text)}</span> <button class="delete-btn" onclick="app.deleteTodo(${todo.id})">删除</button> </li>`).join('');}// 更新统计constactiveCount=this.todos.filter(t=>!t.completed).length;constcompletedCount=this.todos.filter(t=>t.completed).length;this.stats.textContent=`共${this.todos.length}项 | 未完成${activeCount}项 | 已完成${completedCount}项`;}escapeHtml(text){constdiv=document.createElement('div');div.textContent=text;returndiv.innerHTML;}}// 初始化应用constapp=newTodoApp();| 知识点 | 应用 |
|---|---|
| DOM 操作 | getElementById,querySelector,innerHTML |
| 事件监听 | addEventListener |
| ES6 Class | class TodoApp |
| 数组方法 | filter,find,map,forEach |
| 本地存储 | localStorage.setItem,localStorage.getItem |
| 模板字符串 | 动态生成 HTML |
有问题欢迎评论区留言,大家一起讨论!
标签:JavaScript | 实战项目 | 待办清单 | TodoApp | DOM操作 | 本地存储