基于快照的效果通过可替换的 SnapshotCapture 适配器获得像素。核心库不依赖特定的 DOM-to-Canvas 引擎:根入口接受自定义适配器,/snapdom 则提供一个可直接使用的实现。
SnapshotCapture
type SnapshotCapture = (
element: HTMLElement,
context: SnapshotCaptureContext,
) => HTMLCanvasElement | Promise<HTMLCanvasElement>;
interface SnapshotCaptureContext {
operation: 'remove' | 'restore' | 'prepare';
signal: AbortSignal;
invalidate?: boolean;
restoreRootOpacity?: string;
}
适配器必须返回一个包含 element 当前视觉内容的 canvas。canvas 的像素尺寸决定源分辨率;库会独立测量元素的 CSS 边界,并将动画覆盖层放置在这些边界上。
| 上下文字段 | 含义 |
|---|---|
operation | 后台捕获时为 prepare,否则为当前的 remove 或 restore 操作 |
signal | 准备任务、操作或所属实例被取消时触发中止 |
invalidate | 显式准备或缓存失效后,要求捕获引擎刷新自己的缓存 |
restoreRootOpacity | restore() 临时隐藏真实元素之前,根元素的原始计算 opacity |
在执行昂贵工作前检查 signal.aborted;如果底层引擎支持取消,应尽快停止。恢复时应把 restoreRootOpacity 应用于被捕获的根元素,避免捕获其临时隐藏状态。
import Disintegrator, { type SnapshotCapture } from 'vanilla-disintegrate';
const capture: SnapshotCapture = async (element, context) => {
if (context.signal.aborted) {
throw new DOMException('Capture aborted.', 'AbortError');
}
return captureWithMyEngine(element, {
signal: context.signal,
invalidate: context.invalidate,
rootOpacity: context.restoreRootOpacity,
});
};
const effects = new Disintegrator({
preset: 'dust',
capture,
});
如果自定义效果阶段通过 DOM、SVG、CSS、WAAPI 或其他不需要源像素的渲染器实现,请设置 needsSnapshot: false。如果两个阶段都不需要快照,使用 /core 可完全避免引入捕获和粒子依赖。
createSnapdomCapture(options?)
适配器使用 SnapDOM ^3.1.0 及其 SVG 渲染器。SnapdomCaptureOptions 接受当前的 SnapdomOptions,但不包括 canvas 和 engine:每次捕获返回独立拥有的 canvas,效果可以安全地释放它。
显式 width 或 height 优先于 scale;dpr 乘以输出分辨率。例如,{ width: 200, scale: 2, dpr: 2 } 在应用像素预算前请求宽 400 像素的 canvas。
maxCapturePixels 默认为 8,000,000。适配器在栅格化前降低 DPR 以满足预算;false 禁用此限制。预算针对输出位图,不限制 DOM 遍历或资源内嵌的成本。粒子的 renderQuality 在捕获后单独应用。
import Disintegrator, { createSnapdomCapture } from 'vanilla-disintegrate/snapdom';
const capture = createSnapdomCapture({
dpr: 2,
exclude: '[data-capture-ignore]',
});
const effects = new Disintegrator({ preset: 'dust', capture });
适配器默认启用 reconcile: true,以保持快照中的元素尺寸和文本换行。这会增加一次布局测量;设置 reconcile: false 可跳过该步骤。其他设置遵循 SnapDOM 默认值,包括 embedFonts: 'auto'、invalidate: false 和 filterMode: 'hide'。自动 DPR 上限为 2;显式 dpr 可覆盖该限制。符合条件且未改变的捕获使用 SnapDOM 的自动缓存。
图片由 SnapDOM 处理。placeholders: false 为失败图片保留空白位置;fallbackURL 指定替代图片。自定义 filter 原样传递。等待资源可能延迟捕获;请在启动效果前准备自定义懒加载图片。
默认情况下,导出图像与根元素的矩形一致,包含旋转和缩放,不包含阴影或模糊的额外边距。显式 clip、启用 outerShadows 或 outerTransforms: false 使用所请求的 SnapDOM 几何。Safari 使用密度校正来保持内嵌字体和 SVG 清晰。恢复捕获保留根元素原始透明度,同时真实元素继续隐藏。
修改 CSSOM(如 sheet.insertRule() 或 CSSStyleRule.style)后调用 effects.invalidate(element)。这会丢弃预备快照并要求 SnapDOM 刷新样式,即使设置了 snapdom.invalidate: false。显式 prepare() 也要求刷新;clearPrepared() 要求后续捕获刷新。单独调用 capture 时,为本次调用传入 context.invalidate: true,或配置 invalidate: true 以便每次刷新。
预备 canvas 有独立生命周期。默认不观察 DOM 变更:视觉变化后调用 effects.invalidate(),或启用 preparation.observeMutations 来观察 DOM 变化。CSSOM 修改仍需显式失效。插件遵循 SnapDOM 插件契约。
SnapDOM 无法取消正在进行的捕获。适配器拒绝开始前已取消的调用;操作取消后才返回的结果由库负责释放。
/snapdom 构造器
import Disintegrator from 'vanilla-disintegrate/snapdom';
type SnapdomDisintegratorOptions = DisintegratorOptions & {
snapdom?: SnapdomCaptureOptions;
};
const effects = new Disintegrator({
preset: 'vapor',
snapdom: { dpr: 1.5 },
});
snapdom 会把选项传给自动创建的适配器。显式提供 capture 会完全替换该适配器,此时 snapdom 不产生作用。
根入口 vanilla-disintegrate 不会导入 SnapDOM,并且只有所选效果阶段需要快照时才要求提供 capture。
捕获分辨率与渲染质量
捕获和渲染是两个独立阶段:
- 捕获适配器创建源 canvas 并选择其像素密度。
- 粒子渲染器在把源内容转换为 WebGL 纹理和扩展动画表面时应用
renderQuality。
提高 renderQuality 无法恢复源 canvas 中不存在的细节。提高捕获 DPR 会产生更多源像素,因此会增加捕获时间、内存占用、纹理上传开销,并可能增加粒子准备成本。
任何 DOM-to-Canvas 引擎都不能保证逐像素复现浏览器的原始渲染。文本栅格化、浏览器缩放、滤镜、嵌入内容和跨域资源的已知差异请参阅限制章节。