Пользовательский эффект — это пара полноценных анимаций. Vanilla Disintegrate предоставляет геометрию, снимок, отмену, cleanup и контракт для подключения аудио; способ рендеринга и звук выбираете вы.
Определить обе фазы
import { defineEffect } from 'vanilla-disintegrate';
function createLayerClone(element: HTMLElement, layer: HTMLElement) {
const visual = element.cloneNode(true) as HTMLElement;
Object.assign(visual.style, {
height: '100%',
inset: '0',
margin: '0',
pointerEvents: 'none',
position: 'absolute',
width: '100%',
});
layer.append(visual);
return visual;
}
const pulse = defineEffect({
remove: {
needsSnapshot: false,
animate({ element, layer }) {
return createLayerClone(element, layer).animate(
[
{ opacity: 1, transform: 'scale(1)' },
{ opacity: 0, transform: 'scale(.6) rotate(8deg)' },
],
{ duration: 420, easing: 'cubic-bezier(.4, 0, 1, 1)' },
);
},
},
restore: {
needsSnapshot: false,
animate({ element, layer }) {
return createLayerClone(element, layer).animate(
[
{ opacity: 0, transform: 'scale(.6) rotate(-8deg)' },
{ opacity: 1, transform: 'scale(1) rotate(0)' },
],
{ duration: 520, easing: 'cubic-bezier(0, 0, .2, 1)' },
);
},
},
});
effects.remove(element, { effect: pulse });
effects.restore(insertedElement, { effect: pulse });
needsSnapshot: false гарантирует, что для этой фазы не запускаются capture и SnapDOM.
Контекст анимации
Фабрика получает operation, реальный element, конечный bounds, изолированный layer, snapshot, ленивый visual, AbortSignal, random(), флаг reducedMotion и addCleanup(fn).
При восстановлении bounds всегда описывает новое место после вставки, а не старую позицию удаления.
Допустимые результаты
Фабрика может вернуть Web Animation, Promise, null или контроллер с finished, cancel() и dispose(). Контроллер также может передать свой визуальный element, duration и layoutDelay.
Этого достаточно для CSS/WAAPI, Canvas-цикла, SVG, WebGL и сторонних движков. dispose() вызывается при любом результате и должен освобождать ресурсы рендерера.
Именованный эффект
const effects = new Disintegrator({
effects: { pulse },
effect: 'pulse',
});
effects.remove(element);
Прямые объекты и зарегистрированные имена используют тот же контракт, что и четыре встроенных эффекта.
Свой звук
const effect = defineEffect({
remove: {
animate: removeAnimation,
sound: { src: '/sounds/remove.ogg', gain: 0.35 },
},
restore: {
animate: restoreAnimation,
sound: ({ signal }) => startMyAudioEngine(signal),
},
});
Поддерживаются URL, ArrayBuffer, AudioBuffer, объект параметров и фабрика своего плеера. Ошибка аудио не прерывает визуальную или DOM-операцию.