Popper.js использует концепцию модификаторов для
управления позиционированием элементов. Модификаторы представляют собой
объекты с определёнными свойствами и функциями, которые изменяют
поведение Popper на различных этапах жизненного цикла.
Понимание порядка их выполнения критично для создания сложных кастомных
сценариев позиционирования.
Каждый модификатор в Popper.js выполняется в рамках заранее определённых фаз:
fn на этом этапе.main.Каждый модификатор указывает свою фазу через свойство
phase. Попытка изменить позицию в фазе read не
сработает, так как модификатор в read ещё не применяет
вычисления к DOM.
Кастомный модификатор определяется как объект со следующими ключевыми свойствами:
const customModifier = {
name: 'customModifier', // уникальное имя модификатора
enabled: true, // включение/отключение
phase: 'main', // фаза выполнения
requires: ['offset'], // зависимости от других модификаторов
fn({ state, options, name }) {
// основная функция модификатора
},
effect({ state, options, name }) {
// побочные эффекты (например, обработка событий)
return () => {
// функция очистки эффектов
};
}
};
name – используется для идентификации и связывания с
другими модификаторами.enabled – контролирует выполнение. Если
false, модификатор пропускается.phase – определяет момент выполнения.requires и requiresIfExists – гарантируют,
что необходимые модификаторы будут выполнены до текущего.fn – основная функция, выполняющая вычисления и
изменения состояния.effect – используется для установки побочных эффектов и
очистки ресурсов.Popper.js выполняет модификаторы в следующем порядке:
Сортировка по phase согласно жизненному циклу
(beforeRead, read, afterRead,
beforeMain, main, afterMain,
beforeWrite, write,
afterWrite).
Внутри каждой фазы модификаторы сортируются по dependencies:
requires, выполняются до
текущего.После сортировки модификаторы последовательно вызываются функцией
fn или effect.
Пример зависимости: если модификатор flip зависит от
preventOverflow, порядок гарантирует, что сначала
корректировка границ произойдёт через preventOverflow, а
затем flip может корректировать позицию.
Для стабильной работы кастомного модификатора нужно соблюдать три правила:
Указывать фазу, соответствующую выполняемой логике
mainwritereadЯвно указывать зависимости
Использовать state вместо прямого обращения
к DOM
state.rects,
state.modifiersData и state.elements.write.const offsetModifier = {
name: 'customOffset',
enabled: true,
phase: 'main',
requires: ['computeStyles'],
fn({ state, options }) {
const offset = options.offset || 10;
const popper = state.elements.popper;
const reference = state.elements.reference;
state.modifiersData.customOffset = {
top: reference.offsetTop + offset,
left: reference.offsetLeft + offset
};
// Popper сам применит координаты в фазе write
}
};
В этом примере:
requires: ['computeStyles'] гарантирует, что стили уже
рассчитаны.state.modifiersData для
последующей фазы write.fn, что
соответствует архитектуре Popper.js.read)main)afterMain)beforeWrite)write)afterWrite)Понимание этой схемы позволяет создавать сложные, взаимозависимые модификаторы, которые корректно взаимодействуют с внутренними модификаторами Popper.js и не ломают жизненный цикл позиционирования.