JavaScript 本地存储与动态数据渲染实战案例

JavaScript 本地存储与动态数据渲染实战案例

一、案例概述

在前端开发中,本地存储(localStorage) 是无需后端数据库即可实现数据持久化的核心技术,动态数据渲染则是前端页面展示数据的基础能力。本案例通过一个轻量化的「待办事项(TODO)管理工具」,结合两者实现完整功能:用户添加、删除、标记完成待办事项,所有数据自动保存到浏览器本地存储,刷新页面后数据不丢失,同时通过JavaScript动态将数据渲染到页面。

本案例适合前端初学者,覆盖JavaScript DOM操作、本地存储API、数据逻辑处理、事件绑定等核心知识点,无需依赖任何框架,纯原生代码即可运行,可直接部署到本地浏览器使用。

二、核心技术知识点

  1. localStorage本地存储:浏览器提供的持久化存储方案,存储键值对数据,数据永久生效(除非手动清除),存储容量约5MB;
  2. DOM操作:通过JavaScript获取、创建、修改、删除HTML元素,实现页面动态更新;
  3. 事件监听:绑定点击、提交等事件,实现用户交互响应;
  4. 数据处理:数组增删改查、JSON序列化与反序列化(localStorage仅支持字符串存储);
  5. 页面初始化:刷新页面时自动读取本地数据并渲染。

三、实现环境

  • 编辑器: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的数据,更新本地存储。

六、功能测试步骤

  1. 将代码复制到文本编辑器,保存为.html文件;
  2. 用浏览器打开该文件,输入待办内容点击「添加」,或按回车快速添加;
  3. 点击待办文本,标记为已完成(显示删除线);
  4. 点击「删除」按钮,移除对应事项;
  5. 刷新浏览器页面,所有数据保持不变,验证本地存储生效。

七、案例扩展方向

  1. 增加编辑功能:支持修改已添加的待办事项;
  2. 增加筛选功能:区分显示全部、未完成、已完成事项;
  3. 增加清空全部功能:一键清除所有待办数据;
  4. 样式优化:添加动画效果、响应式布局适配移动端。

八、总结

本案例通过原生JavaScript实现了本地存储与动态数据渲染的完整闭环,核心是数据驱动视图:所有交互基于数据数组操作,视图根据数据自动更新,同时通过localStorage完成数据持久化。该模式是前端开发的基础逻辑,掌握后可快速上手Vue、React等主流框架,也能独立开发轻量化前端工具。

相关推荐
m0_50272495几秒前
vue3生成pdf
前端·javascript·vue.js·pdf
楼田莉子2 分钟前
C#学习之C#入门学习
开发语言·后端·学习·c#
我命由我123452 分钟前
PHP - PHP 简易 Web 服务器、基础接口开发
服务器·开发语言·前端·php·intellij-idea·idea·intellij idea
Reload.3 分钟前
CZ航司,shopping JS逆向 acw_sc__v2
开发语言·javascript·python·网络爬虫·ecmascript
码界筑梦坊4 分钟前
130-基于Python的体育用品销售数据可视化分析系统
开发语言·python·信息可视化·flask·毕业设计
码界筑梦坊5 分钟前
131-基于Flask的美国新泽西州自动售货机销售数据可视化分析系统
开发语言·python·信息可视化·数据分析·flask·毕业设计
努力努力再努力wz6 分钟前
【QT入门系列】QWidget 六大常用属性详解:windowOpacity、cursor、font、focus、toolTip 与 styleSheet
android·开发语言·数据结构·c++·qt·mysql·算法
神仙别闹9 分钟前
基于MFC(C++)实现(界面)学委作业管理系统
开发语言·c++·mfc
三品吉他手会点灯9 分钟前
C语言学习笔记 - 41.数据类型 - scanf函数核心知识点复习
c语言·开发语言·笔记·学习
撩得Android一次心动10 分钟前
C语言基础笔记3【个人用】
android·c语言·开发语言·笔记