JavaScript 本地存储与动态数据渲染实战案例
一、案例概述
在前端开发中,本地存储(localStorage) 是无需后端数据库即可实现数据持久化的核心技术,动态数据渲染则是前端页面展示数据的基础能力。本案例通过一个轻量化的「待办事项(TODO)管理工具」,结合两者实现完整功能:用户添加、删除、标记完成待办事项,所有数据自动保存到浏览器本地存储,刷新页面后数据不丢失,同时通过JavaScript动态将数据渲染到页面。
本案例适合前端初学者,覆盖JavaScript DOM操作、本地存储API、数据逻辑处理、事件绑定等核心知识点,无需依赖任何框架,纯原生代码即可运行,可直接部署到本地浏览器使用。
二、核心技术知识点
- localStorage本地存储:浏览器提供的持久化存储方案,存储键值对数据,数据永久生效(除非手动清除),存储容量约5MB;
- DOM操作:通过JavaScript获取、创建、修改、删除HTML元素,实现页面动态更新;
- 事件监听:绑定点击、提交等事件,实现用户交互响应;
- 数据处理:数组增删改查、JSON序列化与反序列化(localStorage仅支持字符串存储);
- 页面初始化:刷新页面时自动读取本地数据并渲染。
三、实现环境
- 编辑器:VS Code(任意文本编辑器均可)
- 运行环境:Chrome/Firefox等现代浏览器
- 技术栈:HTML5 + CSS3 + 原生JavaScript(无第三方依赖)
四、完整代码实现
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>TODO本地存储管理工具</title>
<style>
* {margin: 0; padding: 0; box-sizing: border-box; font-family: Arial, sans-serif;}
.todo-container {width: 500px; margin: 50px auto; padding: 20px; border: 1px solid #eee; border-radius: 8px;}
.input-box {display: flex; gap: 10px; margin-bottom: 20px;}
#todo-input {flex: 1; padding: 8px 12px; border: 1px solid #ddd; border-radius: 4px;}
#add-btn {padding: 8px 16px; background: #409eff; color: white; border: none; border-radius: 4px; cursor: pointer;}
#add-btn:hover {background: #337ecc;}
.todo-list {list-style: none;}
.todo-item {display: flex; justify-content: space-between; align-items: center; padding: 10px; border-bottom: 1px solid #eee;}
.todo-text {cursor: pointer;}
.completed {text-decoration: line-through; color: #999;}
.del-btn {color: #f56c6c; cursor: pointer; border: none; background: none;}
</style>
</head>
<body>
<div class="todo-container">
<h2>待办事项管理</h2>
<div class="input-box">
<input type="text" id="todo-input" placeholder="请输入待办事项">
<button id="add-btn">添加</button>
</div>
<ul class="todo-list" id="todo-list"></ul>
</div>
<script>
// 获取DOM元素
const todoInput = document.getElementById('todo-input');
const addBtn = document.getElementById('add-btn');
const todoList = document.getElementById('todo-list');
// 初始化:读取本地存储数据
let todos = JSON.parse(localStorage.getItem('todos')) || [];
// 页面加载时渲染数据
window.addEventListener('DOMContentLoaded', renderTodoList);
// 添加按钮点击事件
addBtn.addEventListener('click', addTodo);
// 回车快捷添加
todoInput.addEventListener('keydown', (e) => e.key === 'Enter' && addTodo());
/**
* 添加待办事项
*/
function addTodo() {
const text = todoInput.value.trim();
if (!text) return alert('请输入内容!');
// 创建新待办对象
const newTodo = {
id: Date.now(), // 唯一ID
text: text,
completed: false // 完成状态
};
todos.push(newTodo); // 追加到数组
saveToLocal(); // 保存到本地
renderTodoList(); // 重新渲染页面
todoInput.value = ''; // 清空输入框
}
/**
* 渲染待办列表到页面
*/
function renderTodoList() {
todoList.innerHTML = ''; // 清空原有内容
todos.forEach(todo => {
const li = document.createElement('li');
li.className = `todo-item ${todo.completed ? 'completed' : ''}`;
li.innerHTML = `
<span class="todo-text" data-id="${todo.id}">${todo.text}</span>
<button class="del-btn" data-id="${todo.id}">删除</button>
`;
todoList.appendChild(li);
});
// 绑定状态切换和删除事件
bindTodoEvents();
}
/**
* 绑定待办事项交互事件
*/
function bindTodoEvents() {
// 切换完成状态
document.querySelectorAll('.todo-text').forEach(item => {
item.addEventListener('click', toggleComplete);
});
// 删除事项
document.querySelectorAll('.del-btn').forEach(btn => {
btn.addEventListener('click', deleteTodo);
});
}
/**
* 切换待办事项完成状态
*/
function toggleComplete(e) {
const id = parseInt(e.target.dataset.id);
todos = todos.map(todo => {
if (todo.id === id) todo.completed = !todo.completed;
return todo;
});
saveToLocal();
renderTodoList();
}
/**
* 删除待办事项
*/
function deleteTodo(e) {
const id = parseInt(e.target.dataset.id);
todos = todos.filter(todo => todo.id !== id);
saveToLocal();
renderTodoList();
}
/**
* 保存数据到localStorage
*/
function saveToLocal() {
localStorage.setItem('todos', JSON.stringify(todos));
}
</script>
</body>
</html>
五、代码核心解析
1. 本地存储数据处理
- 读取数据:
JSON.parse(localStorage.getItem('todos')) || [],本地无数据时返回空数组,避免报错; - 保存数据:
localStorage.setItem('todos', JSON.stringify(todos)),将数组转为JSON字符串存储(localStorage不支持直接存储对象/数组)。
2. 动态渲染逻辑
- 每次数据变更(添加、删除、状态切换)后,清空列表容器,遍历数据数组重新创建DOM元素;
- 通过自定义
data-id属性绑定数据唯一标识,实现精准操作对应事项。
3. 交互功能实现
- 添加功能:校验输入内容,生成唯一ID,追加到数组并保存;
- 状态切换:点击文本切换
completed状态,添加删除线样式; - 删除功能:过滤掉对应ID的数据,更新本地存储。
六、功能测试步骤
- 将代码复制到文本编辑器,保存为
.html文件; - 用浏览器打开该文件,输入待办内容点击「添加」,或按回车快速添加;
- 点击待办文本,标记为已完成(显示删除线);
- 点击「删除」按钮,移除对应事项;
- 刷新浏览器页面,所有数据保持不变,验证本地存储生效。
七、案例扩展方向
- 增加编辑功能:支持修改已添加的待办事项;
- 增加筛选功能:区分显示全部、未完成、已完成事项;
- 增加清空全部功能:一键清除所有待办数据;
- 样式优化:添加动画效果、响应式布局适配移动端。
八、总结
本案例通过原生JavaScript实现了本地存储与动态数据渲染的完整闭环,核心是数据驱动视图:所有交互基于数据数组操作,视图根据数据自动更新,同时通过localStorage完成数据持久化。该模式是前端开发的基础逻辑,掌握后可快速上手Vue、React等主流框架,也能独立开发轻量化前端工具。