import { tryOnMounted, tryOnUnmounted } from '@vueuse/core'; import { snapdom } from '@zumer/snapdom'; export interface SnapshotOption { immediate?: boolean; } type SnapshotTspl = (total?: number) => string; type SnapshotTemplate = (base64: string) => SnapshotTspl; export function useSnapshot

>(loader: () => Promise<{ default: Component }>, props?: P, option?: SnapshotOption) { const snapshot = shallowRef(); const tspl = shallowRef(); let app: ReturnType | null = null; let container: HTMLDivElement | null = null; const mounted = (component: Component, _props?: Partial

) => { if (container == null) return; const { promise, resolve } = Promise.withResolvers(); app = createApp(component, { ...props, ..._props, onRendered: resolve }); app.mount(container); return promise; }; const unmounted = () => { app?.unmount(); app = null; }; const capture = async (template?: SnapshotTemplate) => { if (container == null) return; const dom = await snapdom(container, { scale: 1 }); const img = await dom.toPng({ scale: 2 }); snapshot.value = img.src; tspl.value = template?.(img.src); }; async function render(props?: Partial

, forced = false): Promise<{ snapshot: string; tspl: SnapshotTspl }> { if (forced) unmounted(); if (forced || !snapshot.value) { const { default: component } = await loader(); const tspl = await mounted(component, props); await capture(tspl); unmounted(); } return { snapshot: snapshot.value!!, tspl: tspl.value!!, }; } tryOnMounted(() => { container = document.createElement('div'); container.style.position = 'fixed'; container.style.left = '-99999px'; container.style.top = '-99999px'; container.style.zIndex = '-1'; document.body.appendChild(container); if (option?.immediate) render().then(); }); tryOnUnmounted(() => { if (container) document.body.removeChild(container); container = null; unmounted(); snapshot.value = ''; tspl.value = void 0; }); return { snapshot, tspl, render }; }