Vanilla Disintegratev1.6.1
RU
На этой странице

Disintegrator объединяет одну полную визуальную конфигурацию, необязательное аудио, захват, анимацию layout, фоновую подготовку и хранилище удалённых узлов.

Entry points

Entry pointСодержимое во время выполненияДополнительная зависимость
vanilla-disintegrate/coreDisintegrator, вспомогательные функции эффектов и пресетов, все публичные типыНет
vanilla-disintegrate/particlesФабрики частиц, визуальные пресеты и типы частицНет
vanilla-disintegrate/soundsURL четырёх встроенных аудиофайлов и типы звукаНет
vanilla-disintegrateDisintegrator, четыре полных пресета, частицы, звуки, helpers и публичные типыНет
vanilla-disintegrate/snapdomКорневой API со SnapDOM в качестве стандартного адаптера захвата@zumer/snapdom

Корневой entry point и /snapdom регистрируют четыре полных встроенных пресета. Только /snapdom предоставляет адаптер захвата; /core содержит жизненный цикл без встроенных пресетов, частиц, встроенных звуковых файлов и захвата. Ни один entry point не выбирает пресет по умолчанию. Специализированные экспорты подробно описаны на страницах частиц, захвата и аудио.

Конструктор

import Disintegrator, { createParticleEffect } from 'vanilla-disintegrate/snapdom';

const ready = new Disintegrator({ preset: 'dust' });
const custom = new Disintegrator({ effect: createParticleEffect() });

Нужно передать ровно одно из двух: preset или effect.

type DisintegratorOptions =
  | { preset: PresetSelection; effect?: never; sound?: false; fallback?: FallbackEffectDefinition }
  | { preset?: never; effect: EffectDefinition; sound?: false | SoundSelection; fallback?: FallbackEffectDefinition };

Пресет — неделимый выбор визуала и аудио. Его можно заглушить через sound: false, но нельзя совместить с заменяющей анимацией или другим звуком. Пользовательский эффект — объект с полными фазами remove и restore; без пары звуков он бесшумный.

Общие опции:

ОпцияТипПо умолчаниюНазначение
presetsRecord<string, PresetDefinition>{}Добавляет полные пресеты, доступные через preset
layoutboolean | LayoutOptionstrueПеремещает соседей на новые позиции после удаления
preparationboolean | PreparationOptionsvisible-idleГотовит снимки зарегистрированных элементов
audioPreparationfalse | 'immediate' | 'idle' | AudioPreparationOptions'idle'Управляет подготовкой и бюджетом владения декодированным аудио
audioWaitTimeoutnumber | false1500Максимальное ожидание аудио перед продолжением без звука
respectReducedMotionbooleantrueПропускает анимацию при запросе уменьшенного движения
fallbackFallbackEffectDefinition—Бесшумно заменяет фазу, которой недоступен WebGL2
captureSnapshotCaptureSnapDOM¹Превращает элемент в canvas для эффектов, которым нужен снимок
overlayRootHTMLElement | () => HTMLElementdocument.bodyПринимает fixed-слои анимации
zIndexnumber2147483646Задаёт уровень слоя
random() => numberMath.randomИнициализирует воспроизводимый поток случайных чисел для операции
snapdomSnapdomCaptureOptions—Настраивает toCanvas() SnapDOM; доступно только из /snapdom
onTrigger(context) => void—Вызывается после проверки и до захвата
onStart(context) => void—Вызывается после изменения DOM при старте воспроизведения
onComplete(context) => void—Вызывается после нормального завершения визуальной фазы
onError(error, context) => void—Получает изолированные ошибки захвата, анимации, звука и колбэков

¹ SnapDOM используется по умолчанию только в /snapdom. Корневой entry point и /core требуют capture, если выбранному эффекту нужен снимок.

Ошибки фоновой подготовки сообщают context.operation === 'prepare'; ошибки операций сообщают remove или restore.

LayoutOptions

Анимация раскладки использует технику FLIP, чтобы после удаления переместить затронутые элементы с их прежних позиций.

ПараметрТипПо умолчаниюНазначение
enabledbooleantrueВключает анимацию раскладки, не заменяя остальные значения по умолчанию
durationnumber300Длительность анимации перестроения в миллисекундах
easingstring'cubic-bezier(0.22, 1, 0.36, 1)'CSS timing function для WAAPI
containerHTMLElement | (element) => HTMLElement | nullРодитель целиЗадаёт систему координат и необязательную цель анимации высоты
siblings'following' | 'all' | (element, container) => HTMLElement[]'following'Выбирает участвующие дочерние элементы
animateContainerbooleantrueАнимирует изменившуюся высоту контейнера

layout: false отключает анимацию перестроения. layout применяется только к remove(); при восстановлении вставленный элемент анимируется в своей итоговой позиции. Отрицательный duration приводится к нулю, а нечисловой — к значению по умолчанию.

PreparationOptions

ПараметрТипПо умолчаниюНазначение
strategy'immediate' | 'idle' | 'visible-idle''visible-idle'Определяет, когда можно захватывать зарегистрированные элементы
shouldPrepare(element) => boolean() => trueФильтрует элементы до постановки в очередь
rootElement | Document | nullnullКорень Intersection Observer
rootMarginstring'300px 0px'Запускает visible-idle до входа элемента во viewport
concurrencynumber1Максимум одновременных захватов; целое число от 1 до 8
invalidateOnResizebooleantrueИнвалидирует подготовленный снимок при изменении размеров
observeMutationsbooleanfalseСледит за изменениями поддерева и событиями загрузки потомков
idleTimeoutnumber750Максимальное ожидание requestIdleCallback в миллисекундах
fallbackDelaynumber250Задержка при отсутствии idle callbacks
scrollSettlenumber120Пауза после прокрутки до фоновой работы
animationSettlenumber400Максимальное ожидание активных анимаций элемента перед захватом
cachePixelBudgetnumber8_000_000Ёмкость LRU в физических пикселях canvas

preparation: false отключает автоматическую подготовку, но не явные вызовы prepare(). Отрицательные значения времени и бюджета кэша приводятся к нулю, а нечисловые — к значениям по умолчанию.

AudioPreparationOptions

ПараметрТипПо умолчаниюНазначение
strategy'immediate' | 'idle''idle'Определяет момент загрузки и декодирования нативного аудио
soundsSoundPreparationSelectionЗвук экземпляраВыбирает звуки для подготовки вместо звука экземпляра
cacheByteBudgetnumber8 * 1024 * 1024Бюджет владения декодированным PCM в LRU одного экземпляра

audioPreparation: false отключает автоматическую работу. Явная подготовка аудио остаётся доступной. Отрицательный бюджет кэша приводится к нулю.

Полные пресеты

import Disintegrator, { createParticleEffect, definePreset } from 'vanilla-disintegrate/snapdom';

const dissolve = definePreset({
  effect: createParticleEffect({
    remove: { curve: 'float' },
    restore: { curve: 'settle' },
  }),
  sound: {
    remove: { src: '/audio/out.ogg', volume: 0.4 },
    restore: { src: '/audio/in.ogg', volume: 0.4 },
  },
});

const effects = new Disintegrator({
  preset: 'dissolve',
  presets: { dissolve },
});

definePreset() замораживает пресет, визуальные фазы и объекты настроек нативного звука, не замораживая бинарные аудиоданные пользователя.

const builtInPresets: Readonly<Record<'dust' | 'scatter' | 'vapor' | 'wind', Readonly<PresetDefinition>>>;

builtInPresets экспортируется корневым entry point и /snapdom. Каждое значение — полный замороженный пресет частиц и аудио. Entry point /particles вместо него экспортирует particlePresets, содержащий только визуальную конфигурацию.

Контракт пользовательского эффекта

import { defineEffect } from 'vanilla-disintegrate/core';

interface EffectPhase {
  requires?: 'webgl2';
  needsSnapshot?: boolean;
  animate: AnimationFactory;
}

interface EffectDefinition {
  remove: EffectPhase;
  restore: EffectPhase;
}

const effect = defineEffect({
  remove: { needsSnapshot: false, animate: removeFactory },
  restore: { needsSnapshot: false, animate: restoreFactory },
});

needsSnapshot по умолчанию равен true. defineEffect() замораживает эффект и объекты обеих фаз, сохраняя их узкий выведенный TypeScript-тип.

Резервный эффект WebGL2

createParticleEffect() и встроенные пресеты автоматически помечают свои фазы как requires: 'webgl2'. Перед захватом библиотека проверяет доступность WebGL2. Если он выключен или недоступен, fallback запускается вместо основной фазы и не создаёт ненужный Canvas-снимок.

import Disintegrator, { defineEffect } from 'vanilla-disintegrate/snapdom';

const fade = defineEffect({
  remove: {
    needsSnapshot: false,
    animate: ({ element }) => element.animate([{ opacity: 1 }, { opacity: 0 }], { duration: 180 }),
  },
  restore: {
    needsSnapshot: false,
    animate: ({ element }) => element.animate([{ opacity: 0 }, { opacity: 1 }], { duration: 180 }),
  },
});

const effects = new Disintegrator({ preset: 'dust', fallback: fade });

Fallback подходит и к пресетам, и к любому пользовательскому эффекту, фаза которого объявляет requires: 'webgl2'. Он может использовать CSS, WAAPI, Canvas 2D, SVG или другой рендерер и по умолчанию работает без звука. TypeScript не позволяет передать в fallback ещё одну WebGL2-фазу; JavaScript-конфигурация проходит такую же проверку в рантайме. Если рендерер частиц не сможет запуститься после предварительной проверки, библиотека попробует fallback после уже созданного снимка.

Фабрика анимации получает AnimationContext:

ПолеТипЗначение
operation'remove' | 'restore'Активная фаза
elementHTMLElementИсходный элемент приложения
layerHTMLElementПустой позиционированный слой, принадлежащий библиотеке
snapshotHTMLCanvasElement | nullИсходный снимок либо null для фазы без снимка
visualHTMLCanvasElement | nullЛениво создаваемая полноразмерная копия snapshot
boundsDOMRectReadOnlyИтоговая геометрия во viewport, использованная слоем
signalAbortSignalПрерывается при отмене или уничтожении экземпляра
reducedMotionfalseЗапросы уменьшенного движения пропускаются до вызова фабрики
random() => numberПсевдослучайный поток отдельной операции
addCleanup(callback: () => void) => voidРегистрирует очистку для завершения, отмены и ошибки

AnimationFactory может вернуть Web Animation, любой PromiseLike, контроллер AnimationPlayback либо null, если анимацию создать не удалось.

interface AnimationPlayback {
  finished: PromiseLike<unknown>;
  element?: HTMLElement;
  duration?: number;
  layoutDelay?: number;
  cancel?(): void;
  dispose?(): void;
}

element добавляется в layer, если у него ещё нет родителя. duration синхронизирует нативное аудио, layoutDelay задерживает перестроение при удалении, cancel() останавливает воспроизведение, а dispose() освобождает ресурсы рендерера при любом варианте завершения.

remove(target, options?)

Отсоединяет найденный элемент и синхронно возвращает EffectOperation.

remove(target: EffectTarget, options?: RemoveOptions): EffectOperation;
const operation = effects.remove('.card', {
  preset: 'scatter',
  sound: false,
  retain: true,
  layout: { duration: 260 },
  detach: (element) => element.remove(),
});

target может быть HTMLElement или строкой-селектором. Отсутствующий селектор выбрасывает исключение до начала операции.

detach заменяет стандартный commit через element.remove(). Используйте его, когда реактивный рендерер должен удалить узел через своё состояние. Если callback выбросит ошибку, она попадёт в onError, а библиотека безопасно выполнит нативное удаление.

restore(target, options?)

Анимирует подключённый и измеримый элемент в его текущей геометрии.

restore(target: EffectTarget, options?: RestoreOptions): EffectOperation;
const operation = effects.restore(element, {
  preset: 'scatter',
  sound: false,
});

Метод выбрасывает исключение, если элемент отсоединён либо имеет нулевую ширину или высоту.

Для любой операции передайте один полный preset, один пользовательский effect с необязательным определением звука этой фазы или ничего, чтобы унаследовать конфигурацию экземпляра либо сохранённого узла. Унаследованный звук и звук пресета можно только заглушить через sound: false.

Параметры операций

ПараметрГде доступенЗначение
presetОбе операцииВыбирает зарегистрированное имя или полный пресет, переданный напрямую
effectОбе операцииВыбирает полный пользовательский эффект; несовместим с preset
soundОбе операцииДобавляет звук фазы к явному пользовательскому эффекту либо заглушает через false
onTriggerОбе операцииДобавляет callback операции перед захватом
onStartОбе операцииДобавляет callback операции после изменения DOM
onCompleteОбе операцииДобавляет callback операции после нормального завершения визуала
onErrorОбе операцииДобавляет изолированный callback ошибок
retainУдалениеСохраняет отсоединённый оригинал под operation.removalId
layoutУдалениеВключает или переопределяет анимацию раскладки для этого удаления
detachУдалениеЗаменяет стандартный commit через element.remove()

Колбэки операции выполняются дополнительно к колбэкам экземпляра. Если не передан ни preset, ни effect, визуал и звук наследуются; унаследованный звук и звук пресета можно заглушить, но нельзя заменить независимо.

Сохранённые элементы

const element = effects.take(removalId); // HTMLElement | null
const discarded = effects.discard(removalId); // boolean
const count = effects.discardAll(); // number

take() забирает запись из хранилища. discard() и discardAll() освобождают ссылки без вставки содержимого.

Подготовка снимков

const unregister = effects.register(elements);
await effects.prepare(elements);
effects.invalidate(elements);
effects.clearPrepared();

invalidate() обновляет и подготовленные canvas, и кеши движка через context.invalidate. Явный prepare() также запрашивает обновление; после clearPrepared() оно требуется при следующем захвате. Это относится и к изменениям CSSOM, которые не видны DOM-наблюдателям. Пользовательские адаптеры с собственным кешем должны учитывать context.invalidate.

register() следует выбранной стратегии. prepare() захватывает сразу даже при отключённой фоновой подготовке. Повторные регистрации одного элемента используют счётчик ссылок; каждая возвращённая функция отмены освобождает только свою регистрацию.

register() возвращает идемпотентную функцию () => void; prepare() возвращает Promise<void>; invalidate() и clearPrepared() возвращают void.

Подготовка аудио

await effects.prepareAudio({
  remove: { src: 'dust' },
  restore: { src: 'dust', reverse: true },
});
effects.discardPreparedAudio();
effects.clearPreparedAudio();

Без аргумента prepareAudio() и discardPreparedAudio() используют настроенную пару экземпляра. Явные методы работают даже при отключённой автоматической подготовке. Декодированные буферы используют ограниченный LRU владения экземпляра, а загрузки, буферы и AudioContext разделяются между экземплярами.

prepareAudio() возвращает Promise<void>, discardPreparedAudio() — число освобождённых декодированных записей во владении экземпляра, а clearPreparedAudio() — void.

destroy()

effects.destroy();

Отменяет активные операции, останавливает наблюдатели и фоновые задачи, освобождает снимки и владение декодированным аудио, очищает сохранённые узлы. Общий контекст воспроизведения закрывается после уничтожения последнего владельца. Повторный вызов destroy() безопасен; запуск новой работы после него выбрасывает исключение.

EffectOperation

interface EffectOperation {
  readonly operation: 'remove' | 'restore';
  readonly removalId: RemovalId | null;
  readonly finished: Promise<{
    operation: 'remove' | 'restore';
    status: 'completed' | 'cancelled' | 'skipped' | 'rejected';
    removalId: RemovalId | null;
  }>;
  cancel(): void;
}

Handle не открывает элемент и освобождает ссылку на него после завершения.

СтатусДействие с содержимымКогда завершается finished
completedВыполнено; визуальная фаза завершилась нормальноПосле визуальной очистки
cancelledВыполнено; визуал или аудио остановленыПосле очистки отмены
skippedВыполнено без доступной визуальной фазыПосле резервной очистки
rejectedНе начато; DOM не изменёнПосле завершения текущего владельца

Колбэки и приоритет

Колбэки экземпляра выполняются для каждой операции, а колбэки операции — рядом с ними. Приоритет имеет явная конфигурация операции, затем запомненная конфигурация сохранённого узла, затем конфигурация экземпляра. Конкурирующий вызов для уже занятого элемента завершается как rejected после освобождения текущим владельцем.

interface EffectContext {
  operation: 'remove' | 'restore';
  element: HTMLElement;
  overlay: HTMLElement | null;
  removalId: RemovalId | null;
}

interface EffectErrorContext {
  operation: 'remove' | 'restore' | 'prepare';
  element: HTMLElement;
  overlay: HTMLElement | null;
  removalId: RemovalId | null;
}

onTrigger вызывается после проверки и измерения, но до захвата и изменения DOM; его overlay равен null. onStart вызывается после изменения содержимого и начала воспроизведения. onComplete вызывается только после нормального завершения визуала и раскладки. onError получает ошибки подготовки, захвата, анимации, аудио, очистки и пользовательских колбэков, не позволяя им прервать обязательную работу с DOM или очистку.

Редактировать страницу на GitHub