Архитектура плагинов в Tippy.js построена вокруг принципа композиции: базовое поведение тултипа расширяется за счёт независимых модулей, которые внедряются в жизненный цикл экземпляра. Каждый плагин — это объект с набором хуков, позволяющих вмешиваться в различные этапы работы тултипа: от инициализации до уничтожения.
Ключевая идея — инверсия управления. Библиотека предоставляет точки расширения, а плагины реализуют конкретную логику, не изменяя ядро.
Минимальная структура плагина:
const myPlugin = {
name: 'myPlugin',
defaultValue: true,
fn(instance) {
return {
onCreate() {},
onShow() {},
onHide() {},
onDestroy() {}
};
}
};
Экземпляр instance — это центральный объект Tippy, через
который происходит взаимодействие с DOM, состоянием и настройками.
Плагины интегрируются в жизненный цикл тултипа через набор событий.
const logPlugin = {
name: 'logPlugin',
fn(instance) {
return {
onShow() {
console.log('Tooltip is about to show');
},
onHide() {
console.log('Tooltip is about to hide');
}
};
}
};
Объект instance предоставляет доступ к ключевым
компонентам:
fn(instance) {
return {
onCreate() {
instance.popper.classList.add('custom-class');
}
};
}
Плагины могут хранить собственное состояние через замыкание:
const statePlugin = {
name: 'statePlugin',
fn(instance) {
let counter = 0;
return {
onShow() {
counter++;
console.log(counter);
}
};
}
};
Такой подход гарантирует изоляцию состояния каждого экземпляра.
Плагин может вводить собственные параметры, интегрированные в конфигурацию Tippy.
const colorPlugin = {
name: 'color',
defaultValue: 'blue',
fn(instance) {
return {
onCreate() {
instance.popper.style.backgroundColor = instance.props.color;
}
};
}
};
Использование:
tippy(element, {
color: 'red',
plugins: [colorPlugin]
});
Tippy.js поддерживает одновременное использование нескольких плагинов. Они выполняются последовательно.
tippy(element, {
plugins: [pluginA, pluginB]
});
Плагины вызываются в том порядке, в котором они переданы. Это важно при наличии зависимостей между ними.
Каждый плагин должен:
Это достигается за счёт:
Плагины часто манипулируют DOM-элементами тултипа:
const arrowPlugin = {
name: 'arrowPlugin',
fn(instance) {
return {
onCreate() {
const arrow = document.createElement('div');
arrow.className = 'arrow';
instance.popper.appendChild(arrow);
}
};
}
};
Важно учитывать:
Хуки могут содержать асинхронный код:
const asyncPlugin = {
name: 'asyncPlugin',
fn(instance) {
return {
async onShow() {
const data = await fetch('/api/data');
instance.setContent(await data.text());
}
};
}
};
Следует учитывать:
Некоторые хуки позволяют контролировать поведение тултипа:
onShow() {
if (!shouldShow()) {
return false;
}
}
Возврат false отменяет действие.
Tippy.js использует Popper.js для позиционирования, и плагины могут влиять на его конфигурацию:
fn(instance) {
return {
onCreate() {
instance.setProps({
popperOptions: {
modifiers: [
{
name: 'offset',
options: { offset: [0, 20] }
}
]
}
});
}
};
}
Плагин может изменять props в процессе работы:
onShow() {
instance.setProps({
duration: 0
});
}
Это позволяет адаптировать поведение в зависимости от контекста.
Плагины можно комбинировать и переиспользовать:
const plugins = [pluginA, pluginB, pluginC];
Каждый из них решает узкую задачу:
Tippy.js включает ряд встроенных плагинов, реализованных по той же архитектуре:
Они демонстрируют лучшие практики:
При разработке плагинов важно учитывать:
Пример:
fn(instance) {
let cachedValue;
return {
onShow() {
if (!cachedValue) {
cachedValue = computeExpensiveValue();
}
instance.setContent(cachedValue);
}
};
}
Распространённые проблемы:
Рекомендуется:
Архитектура позволяет создавать сложные системы:
Пример паттерна:
const composedPlugin = {
name: 'composed',
fn(instance) {
const subLogic = createSubLogic(instance);
return {
onShow() {
subLogic.run();
}
};
}
};
Такая архитектура делает Tippy.js гибким инструментом, пригодным как для простых тултипов, так и для сложных интерфейсных систем с расширяемой логикой.