用 localStorage 实现任务看板拖拽布局持久化,核心是拖拽结束立即保存各列任务 ID 序列,页面加载时按序还原:1. 任务卡使用稳定语义化 ID;2. 按列存储 ID 数组的 JSON 字符串;3. 加载时缓存节点、解析数据、严格按序插入;4. 仅在 drop 后保存,避免高频写入。

用 localStorage 实现任务看板的拖拽布局持久化,核心是:在每次拖拽结束(dragend 或 drop)后,立即把当前各列(如 To Do / In Progress / Done)中任务卡片的 ID 顺序存入本地;页面加载时再读取并还原 DOM 结构。关键不在“能不能拖”,而在“拖完立刻记、刷新马上还”。
1. 给每张任务卡分配唯一且稳定的 ID
不能用随机数或时间戳作为卡片 ID,否则刷新后无法匹配旧数据。推荐使用语义化 ID,比如 task-123、task-bug-fix-login,或从后端返回的真实主键。确保同一张卡片无论何时加载,ID 都不变。
- 创建卡片时就写死
data-id="task-456" - 避免用
index或Math.random()生成 ID - 如果卡片来自 API,直接复用返回的
id字段
2. 按列存储任务 ID 序列(JSON 格式)
不存整个 HTML 或 DOM 结构,只存每列下卡片 ID 的数组。例如:
localStorage.setItem('board-columns', JSON.stringify({"todo": ["task-1", "task-3"],
"in-progress": ["task-2"],
"done": ["task-4", "task-5"]
}));
这样轻量、可读、易调试,也方便后续扩展(比如加排序字段或完成时间)。
立即学习“前端免费学习笔记(深入)”;
- 列容器用统一的
data-column="todo"标识 - 每次
drop后,遍历所有列,收集其子卡片的data-id - 调用
JSON.stringify()存入localStorage,不要直接存对象
3. 页面加载时按序还原卡片位置
在 DOMContentLoaded 或 Vue/React 的 mounted 阶段执行还原逻辑:先读取本地数据,再清空各列内容,最后按数组顺序把对应 ID 的卡片节点插入到目标列中。
- 用
document.querySelectorAll('[data-id]')提前缓存所有卡片节点(用 Map 映射 ID → 元素) - 解析
localStorage.getItem('board-columns'),若为空则用默认布局 - 对每个列,用
appendChild()或insertBefore()严格按数组顺序插入——顺序错一位,整个布局就乱 - 避免用
innerHTML = ...重绘,会丢失事件监听器和表单状态
4. 注意拖拽事件与存储时机的配合
别在 dragstart 或 dragover 中存数据,这些事件高频触发,浪费 I/O。只在真正落定(drop)后保存,并加防抖(可选)防止快速连拖多次写入。
- 监听所有列容器的
drop事件,而非全局 - 在
drop回调末尾调用保存函数,如saveBoardLayout() - 保存前可比对新旧数据,仅当顺序实际变化才写入
localStorage(减少无意义操作) - 记得捕获异常:
try { localStorage.setItem(...) } catch(e) { console.warn('Storage failed') }
不复杂但容易忽略:ID 稳定性、序列化/解析、插入顺序、存储时机。做到这四点,关掉浏览器再打开,任务卡还在原位。



















