DOM截图离线存储:snapDOM 三种落地方式与常见坑
2026/8/24 7:32:10 网站建设 项目流程

DOM截图离线存储:snapDOM 三种落地方式与常见坑

【免费下载链接】snapdomHigh-performance engine for capturing, modifying, and converting DOM elements into any format.项目地址: https://gitcode.com/GitHub_Trending/sn/snapdom

先说场景:你在做一个离线笔记工具,用户断网时想把当前笔记页面存成一张图片,本地保存、随时回看。这时候你需要的是两件事——把 DOM 元素转成图片,再把图片写进浏览器本地存储。snapDOM 是一个高性能的 DOM 截图引擎,能在浏览器里把任意元素转成 SVG、PNG、JPG、WebP 等格式,整个流程在本地执行,不产生网络请求,天然适合离线截图存储。

第一步:从元素拿到可存储的 Blob

snapDOM 的调用入口就一行:传入元素,得到一个带导出方法的对象。下面这段代码演示"截图 + 转 WebP Blob"的最小链路:

import { snapdom } from '@zumer/snapdom' const blob = await snapdom(noteEl, { cache: 'full' }) .toBlob({ format: 'webp', quality: 0.85 }) console.log(blob.size) // 文件大小(字节),可直接判断是否超存储配额

这里有两个值得展开的细节:

  • toBlob内部会先把 SVG 结果画到 canvas,再调canvas.toBlob编码(见 src/exporters/toBlob.js)。format支持pngjpegwebpquality只在有损格式下生效。
  • 选项里的cache: 'full'是四级缓存策略之一(disabled/full/soft/auto),策略归一化和淘汰逻辑在 src/core/cache.js。重复截同一个元素时,full能明显减少重复计算。

如果你的页面图片、背景、字体都来自远端,可以在截图前先预热资源,避免截图时卡在网络请求上:

import { preCache } from '@zumer/snapdom/preCache' await preCache(noteEl, { cache: 'full' }) // 预取 <img>、背景图并内嵌字体

preCache会扫描元素子树,把img和带url(...)的背景提前转成 dataURL 存进缓存(实现见 src/api/preCache.js)。对离线场景尤其有用:有网时把关键资源缓存下来,断网后截图就不会丢图。

三种本地存储落点

拿到 Blob 后,往哪儿存取决于图片大小和使用频率。

方案一:IndexedDB 存大量截图(推荐)

IndexedDB 配额大(通常为可用磁盘空间的 50%~60%),原生支持存 Blob,是离线截图库的主力方案:

function openDB() { return new Promise((resolve, reject) => { const req = indexedDB.open('snapdom-screens', 1) req.onupgradeneeded = () => req.result.createObjectStore('shots', { keyPath: 'id', autoIncrement: true }) req.onsuccess = () => resolve(req.result) req.onerror = () => reject(req.error) }) } const db = await openDB() const tx = db.transaction('shots', 'readwrite') tx.objectStore('shots').add({ ts: Date.now(), blob }) await new Promise((r, j) => { tx.oncomplete = r; tx.onerror = () => j(tx.error) })

方案二:File System Access API 存到磁盘

Chrome/Edge 支持showSaveFilePicker,让用户像"另存为"一样把截图写到本地文件系统,适合导出单张大图:

const handle = await window.showSaveFilePicker({ suggestedName: `note-${Date.now()}.webp`, types: [{ description: 'WebP 图片', accept: { 'image/webp': ['.webp'] } }] }) const writable = await handle.createWritable() await writable.write(blob) await writable.close()

注意它必须触发在用户手势里(点击按钮),不能放异步回调深处。

方案三:localStorage 存小图

只适合缩略图级别(几十 KB)。转成 base64 后体积约膨胀 33%,而 localStorage 一般只有 5MB,存 3~4 张 1MP 的 WebP 就接近上限:

const b64 = await new Promise(r => { const fr = new FileReader() fr.onload = () => r(fr.result) fr.readAsDataURL(blob) }) localStorage.setItem('last-shot', b64)

选型速查:

方案容量适合
IndexedDBGB 级截图历史库
File System API磁盘单次导出
localStorage~5MB最近一次快照/缩略图

离线场景的三个常见坑

  1. 透明背景变黑。JPG 和 WebP 不支持透明通道,snapDOM 在生成有损格式时若没指定backgroundColor,会自动填#ffffff(归一化逻辑在 src/core/context.js)。如果你的页面是深色主题,截图前显式设置backgroundColor更稳妥。
  2. 字体没加载完就截图。离线包里如果用了@font-face,先await document.fonts.ready或依赖preCache的内嵌字体流程,否则截图会退回系统字体。
  3. 批量截图内存飙高。逐张处理、拿到结果后再截下一张;不需要留存的中间 blob 及时用blob.close()(File 对象)或丢弃引用,别把几百张塞进同一个数组再一起存。
for (const el of els) { const blob = await snapdom(el).toBlob({ format: 'jpeg', quality: 0.7 }) await store.add({ ts: Date.now(), blob }) // 存一张、释一张 }

落地建议

  • 格式按内容选:文字为主的卡片用 WebP(压缩比高),需要透明背景用 PNG,纯照片类用 JPG。
  • 给历史库加淘汰策略:按时间倒序遍历 IndexedDB 记录,删掉 30 天前的,或控制总数上限。
  • 断网提示做前置navigator.onLine为 false 时直接走本地存储分支,别等写库失败才兜底。

preCache放在应用启动时跑一次,截图逻辑只依赖本地缓存——这是离线截图最省心的组合。

【免费下载链接】snapdomHigh-performance engine for capturing, modifying, and converting DOM elements into any format.项目地址: https://gitcode.com/GitHub_Trending/sn/snapdom

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询