核心是存可还原的绘制指令序列而非base64图像:记录线、清空等操作为json数组,防抖800ms后存入localstorage;dom加载后校验并重放绘制,导出或清空时及时清理。

用 localStorage 实现离线画板草稿自动备份,核心不是“存图像”,而是“存可还原的绘制指令序列”——因为 localStorage 只支持字符串,且容量有限(通常 5–10MB),直接存 base64 图片既低效又易溢出。真正可靠的做法是:记录用户每一步操作(如笔画起点、终点、粗细、颜色、橡皮擦区域等),结构化保存为 JSON,加载时重放绘制过程。
只存操作数据,不存渲染结果
画板内容本质是一系列绘图命令,比如:
- 画线:{ type: "line", x1: 120, y1: 80, x2: 180, y2: 110, lineWidth: 3, color: "#333" }
- 清空:{ type: "clear" }
- 撤销一步:{ type: "undo" }(实际存时不记 undo,而是删掉最后一条命令)
每次用户落笔、拖动、抬笔(即 mouseup/mouseend 或 touchend 后),把完整路径或关键点封装成对象,追加进一个操作数组。防抖后(延迟 800ms)用 JSON.stringify(operations) 存入 localStorage,键名建议为 canvas-draft-${location.pathname}-${canvasId || 'main'},避免多画板冲突。
DOM 就绪后再恢复,手动触发重绘
不能在 script 标签里立刻读取并 drawImage——此时 canvas 元素可能还没挂载,或尺寸未初始化。必须等 DOMContentLoaded 触发后,再执行:
- 查
localStorage.getItem("canvas-draft-xxx"),校验非 null 且 JSON.parse 不报错 - 检查时间戳(如有):若
savedAt超过 7 天,跳过恢复,防止陈旧指令与新版 API 不兼容 - 获取 canvas 上下文,清空画布,遍历操作数组逐条重绘(注意 lineCap、lineJoin 等上下文状态需同步还原)
- 重绘完成后,调用
canvas.dispatchEvent(new Event('input', { bubbles: true })),让绑定的保存逻辑或 UI 提示能感知“已加载草稿”
提交或清空时及时清理,防重复干扰
画板没有传统“提交”按钮,但常见出口有三个:导出图片、保存为文件、点击「新建画布」。这些动作都应触发清理:
- 导出 PNG 后(
canvas.toDataURL()成功),调用localStorage.removeItem("canvas-draft-xxx") - 用户点「清空画布」,除了清 canvas,也同步清除对应 localStorage 项
- 切换画布模式(如从铅笔切到橡皮),不触发清除;但点击「新建」或路由跳转前,可主动清空
敏感操作如“撤销/重做”本身不写入 localStorage——它们只操作内存中的 operations 数组,最终落盘仍以完整数组为准,避免状态碎片化。
补充防丢兜底:beforeunload 仅提示,不存盘
用户关页前最后一笔可能还在防抖计时器里。可在用户首次绘图时设 let hasUnsaved = true,每次防抖成功保存后置为 false。在 beforeunload 中仅返回提示字符串(如 "画板有未保存内容,确定离开?")。不要在里面调用 localStorage.setItem() 或 await,现代浏览器会忽略异步操作,且该钩子执行窗口极短(约 50ms),强行写入反而容易失败静默。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











