Недавно столкнулся с интересной задачей: нужно создать модальные окна, которые бы рендерились с помощью вызовов функций. После ресерча различных библиотек и статей собрал все ведомые мне способы в одной статье. Под катом подробнее.

Мы специально не будем рассматривать стандартное размещение попапов с помощью teleport и v-show с реактивным состоянием внутри родительского компонента. Данная статья рассматривает случаи, когда попапы не должны засорять другие компоненты данными для своих пропсов. Также мы не будем рассматривать паттерн UIState, где для каждого попапа в сторе (Vuex/Pinia) прописывается состояние открыт ли попап.
Эмиттинг ивентов
Данный способ основывается на паттерне pub/sub. К слову это самый примитивный способ и некрасивый способ, что можно придумать.
Мы можем реализовать паттерн pub/sub сами, это сделать не так уж и сложно, внизу предоставлена примитивная реализация pub/sub, которая будет только вызывать ивенты и подписываться на них.
// Список заранее прописанных ивентов
export enum EmitterEvents {
SHOW_POPUP
}
// Интерфейс для эмиттера (объекта, который будет содержать все функции
// которые нужно вызвать при тригере)
type Emitter = Record<EmitterEvents, Array<() => void>>;
const emitter: Emitter = {
[EmitterEvents.SHOW_POPUP]: []
};
// Используем composable для того чтобы вернуть нужные нам функции
export const useEmitter = () => {
const trigger = (event: EmitterEvents) => emitter[event].forEach(cb => cb());
const bind = (event: EmitterEvents, callback: () => void) => {
if (emitter[event].includes(callback)) {
console.warn('This callback is already in emitter! 