使用localStorage保存仪表盘布局需以组件ID为key设计对象结构,拖拽/缩放结束时防抖写入并try-catch异常,页面加载后在DOM就绪时解析还原,多看板场景用拼接key区分,同时兼容iOS私有模式等限制。

localStorage 能存仪表盘布局,但直接 setItem 一存了之会丢数据、卡页面、跨看板失效——关键在结构设计、写入时机和错误兜底。
用对象而非数组存组件布局,避免重排错位
组件拖拽后顺序变了,如果用数组索引(layout[0])存位置,下次加载时 DOM 顺序可能已变,导致 widget-3 被套上 widget-1 的坐标。必须用组件唯一 ID 当 key:
{ "widget-1": { "x": 42, "y": 87, "width": 320, "height": 180 }, "widget-2": { "x": 370, "y": 25, "width": 260, "height": 160 } }
- ID 建议由后端下发或前端生成稳定 UUID,别用
Math.random()或循环索引 - 字段只存 UI 相关项:
x、y、width、height、zIndex;权限、数据源等敏感字段绝不进 localStorage - 多看板场景下,key 改为
layout-${userId}-${dashboardId},别堆在一个 key 里靠解析区分
拖拽/缩放结束时防抖写入,别在 mousemove 里狂存
用户拖一个组件,mousemove 每秒触发几十次,直接 localStorage.setItem 会阻塞主线程、触发 QuotaExceededError、甚至让 Chrome 报 “The operation is insecure” 错误。
- 监听
dragend或mouseup(缩放场景用resizeend或自定义事件),不是每动一下都存 - 加 300ms 防抖:用
setTimeout缓存一次写入,期间新触发就 clearTimeout 重置 - 必须包
try...catch,捕获QuotaExceededError和SyntaxError(JSON.stringify 失败时) - 失败后可清空旧数据再试一次,或降级为内存缓存 + 提示“本地存储已满,请清理浏览器缓存”
页面加载后安全还原布局,DOM 就绪是前提
在 DOMContentLoaded 或 Vue 的 mounted、React 的 useEffect(() => {}, []) 中读取,但此时组件 DOM 可能还没挂载完(尤其异步加载的 widget)。
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力: - 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面; - 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”; - 提及位于 `apps/console/src/featur
- 先
localStorage.getItem('layout-key'),再JSON.parse();解析失败就用默认布局对象回退 - 遍历 layout 对象时,用
document.getElementById(widgetId)查 DOM,查不到就跳过,别 throw - 设置样式用
el.style.left = layout[widgetId].x + 'px'等,别依赖 CSS-in-JS 的 runtime 注入逻辑(它可能晚于 localStorage 读取) - 若组件用 Web Component 或 Shadow DOM,需确认
style是否能穿透作用域,否则得改用el.setAttribute('data-x', ...)+ CSS 属性选择器
移动端 Safari 和旧版 iOS WebView 的兼容陷阱
iOS 12–14 的私有模式下,localStorage 默认被禁用,调用 setItem 会直接抛 SecurityError,且不触发 catch —— 它连 try 都没进就崩了。
- 写入前先测可用性:
try { localStorage.test = 1; delete localStorage.test; } catch(e) { /* 不可用 */ } - 不可用时,fallback 到
sessionStorage(关闭标签页即丢)或内存对象const fallbackLayout = {} - 别信
'localStorage' in window,它在私有模式下仍为 true,必须实测写入 - Android WebView 低版本(Chrome JSON.stringify 分块压缩
最易被忽略的是:用户手动清空 localStorage 后,你的代码是否还能无报错回退到默认布局?很多实现卡在 JSON.parse(null) 就白屏了——检查 getItem 返回值是否为 null 或空字符串,比检查异常更前置、更可靠。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










