如何使用Vue.js结合localStorage保存ToDo待办任务
Vue版ToDo应用持久化到localStorage的正确实现
核心误区纠正
你之前直接存DOM元素innerHTML的思路,完全不适合Vue的开发模式:
- localStorage要存储的是结构化的业务数据,而非页面渲染出来的HTML字符串
- 存下来的HTML片段没有固定结构,后续根本没法从里面拆分出任务内容、完成状态、唯一标识这类核心信息,所有需要改任务状态、删任务、筛选任务的功能全都会失效
之前的错误写法:
localStorage.setItem('tasks', tasks.innerHTML)
这种写法相当于把页面上已经渲染好的HTML当数据源存了,完全颠倒了逻辑——Vue的核心是先有数据,再根据数据生成DOM,不是反过来把DOM存了当数据源。
具体实现步骤
定义结构化的响应式任务数据
不要直接操作DOM拿内容,先把每个任务定义为带唯一标识、内容、状态的对象,整体存为响应式数组,单个任务的结构参考:{ id: 任务唯一标识(可直接用时间戳生成), content: 任务文本内容, completed: 任务是否完成的布尔值 }初始化时从localStorage读取存量数据
应用启动时先从本地缓存读取已存的任务,没有有效数据就给空数组作为初始值,同时加异常兜底,避免之前存的非法字符串(比如之前的innerHTML内容)导致解析报错:const getStoredTasks = () => { try { // 读取本地缓存的内容,解析成可操作的JSON结构 return JSON.parse(localStorage.getItem('vue-todo-data')) || [] } catch (err) { // 解析失败(比如缓存了之前的非JSON内容)就重置为空数组 return [] } }数据变更时自动同步到localStorage
用Vue的侦听器深度监听任务数组的变化,一旦任务增删改、状态切换,就把最新的任务数组序列化为JSON字符串存入本地缓存:- 一定要开启
deep: true深度监听,不然单个任务内部的状态变更不会触发同步 - localStorage只能存储字符串,对象数组需要用
JSON.stringify()序列化后再存
- 一定要开启
完整可参考代码(Vue3 Composition API 写法)
<template> <div class="todo-app"> <input v-model="newTaskContent" @keyup.enter="addTask" placeholder="输入新任务,按回车添加" /> <ul> <li v-for="task in tasks" :key="task.id" :class="{ completed: task.completed }" @click="toggleTask(task.id)" > {{ task.content }} <button @click.stop="deleteTask(task.id)">删除</button> </li> </ul> </div> </template> <script setup> import { ref, watch } from 'vue' // 新任务输入框的绑定值 const newTaskContent = ref('') // 初始化任务数组:从本地缓存读取有效数据 const tasks = ref(getStoredTasks()) // 深度监听任务数组变化,自动写入本地缓存 watch(tasks, (latestTasks) => { localStorage.setItem('vue-todo-data', JSON.stringify(latestTasks)) }, { deep: true }) // 读取本地缓存的工具函数 function getStoredTasks() { try { return JSON.parse(localStorage.getItem('vue-todo-data')) || [] } catch (err) { return [] } } // 添加新任务 function addTask() { if(!newTaskContent.value.trim()) return tasks.value.push({ id: Date.now(), content: newTaskContent.value.trim(), completed: false }) newTaskContent.value = '' } // 切换任务完成状态 function toggleTask(taskId) { const targetTask = tasks.value.find(item => item.id === taskId) if(targetTask) targetTask.completed = !targetTask.completed } // 删除任务 function deleteTask(taskId) { tasks.value = tasks.value.filter(item => item.id !== taskId) } </script> <style> .completed { text-decoration: line-through; color: #999; } </style>
注意事项
- 本地缓存的存储key不要和之前原生JS版本的key完全重名,避免之前存的innerHTML内容和现在的JSON结构冲突,导致解析报错
- 如果是用Vue2 Options API实现,核心逻辑完全一致:在
data中定义tasks数组(初始化时读本地缓存),在watch中侦听tasks的深层变化,同步写入缓存即可
内容的提问来源于stack exchange,提问作者user14945188
相关产品推荐
相关产品推荐

