# Компонент ModalWindow - Полная документация ## Назначение компонента `ModalWindow` - универсальный компонент для создания модальных окон (диалоговых окон) в приложении. Предоставляет функциональность для отображения контента поверх основного интерфейса с затемнением фона, анимациями и управлением через глобальную шину событий. ## git репозитарий https://gogs.osvoj.ru/s5l.ru/borbad.s5l.ru/src/master/vue/app/shared/ModalWindow/ ## Архитектура компонента ### Структура файлов ``` app/shared/ModalWindow/ ├── index.coffee # Логика компонента ├── index.pug # Шаблон └── index.styl # Стили ``` ## Импорт и регистрация ```coffee # В основном файле приложения (app/temp.coffee) components: 'modal-window': require 'app/shared/ModalWindow' ``` ## Базовое использование ### 1. Простое модальное окно ```pug modal-window( :is-visible="showModal" @close="showModal = false" ) template([body]) h2(class="text-xl font-bold mb-4") Заголовок p Содержимое модального окна ``` ### 2. С кнопками действий ```pug modal-window( :is-visible="showModal" @close="showModal = false" @confirm="handleConfirm" ) template([body]) h2(class="text-xl font-bold mb-4") Подтверждение p Вы уверены, что хотите выполнить это действие? template([footer]) button(@click="$emit('close')" class="btn-secondary") Отмена button(@click="$emit('confirm')" class="btn-primary") Подтвердить ``` ## Полный список props ### `isVisible` (обязательный) - **Тип:** `Boolean` - **Описание:** Управляет видимостью модального окна - **Пример:** ```pug modal-window(:is-visible="isModalOpen") ``` ### `title` (опциональный) - **Тип:** `String` - **По умолчанию:** `''` - **Описание:** Заголовок модального окна - **Пример:** ```pug modal-window(:is-visible="showModal" title="Заголовок окна") ``` ### `size` (опциональный) - **Тип:** `String` - **По умолчанию:** `'md'` - **Допустимые значения:** `'sm'`, `'md'`, `'lg'`, `'xl'`, `'full'` - **Описание:** Размер модального окна - **Пример:** ```pug modal-window(:is-visible="showModal" size="lg") ``` ### `closeOnBackdrop` (опциональный) - **Тип:** `Boolean` - **По умолчанию:** `true` - **Описание:** Закрывать ли окно при клике на подложку - **Пример:** ```pug modal-window(:is-visible="showModal" :close-on-backdrop="false") ``` ### `closeOnEscape` (опциональный) - **Тип:** `Boolean` - **По умолчанию:** `true` - **Описание:** Закрывать ли окно при нажатии Escape - **Пример:** ```pug modal-window(:is-visible="showModal" :close-on-escape="false") ``` ### `showCloseButton` (опциональный) - **Тип:** `Boolean` - **По умолчанию:** `true` - **Описание:** Показывать ли кнопку закрытия - **Пример:** ```pug modal-window(:is-visible="showModal" :show-close-button="false") ``` ### `overlayClass` (опциональный) - **Тип:** `String` - **По умолчанию:** `''` - **Описание:** Дополнительные классы для подложки - **Пример:** ```pug modal-window(:is-visible="showModal" overlay-class="bg-opacity-80") ``` ### `contentClass` (опциональный) - **Тип:** `String` - **По умолчанию:** `''` - **Описание:** Дополнительные классы для контента - **Пример:** ```pug modal-window(:is-visible="showModal" content-class="custom-modal-style") ``` ## События (Events) ### `@close` - **Описание:** Событие закрытия модального окна - **Payload:** `null` - **Пример:** ```pug modal-window(:is-visible="showModal" @close="handleModalClose") ``` ### `@confirm` (опциональный) - **Описание:** Событие подтверждения действия - **Payload:** `null` - **Пример:** ```pug modal-window(:is-visible="showModal" @confirm="handleConfirm") ``` ### `@opened` - **Описание:** Событие полного открытия модального окна (после анимации) - **Payload:** `null` - **Пример:** ```pug modal-window(:is-visible="showModal" @opened="handleModalOpened") ``` ### `@closed` - **Описание:** Событие полного закрытия модального окна (после анимации) - **Payload:** `null` - **Пример:** ```pug modal-window(:is-visible="showModal" @closed="handleModalClosed") ``` ## Слоты (Slots) ### `[body]` (основной слот) - **Описание:** Основное содержимое модального окна - **Пример:** ```pug modal-window(:is-visible="showModal") template([body]) h2 Заголовок p Основной контент form input(type="text" placeholder="Введите данные") button(type="submit") Отправить ``` ### `[header]` (опциональный) - **Описание:** Заголовочная область модального окна - **Пример:** ```pug modal-window(:is-visible="showModal") template([header]) div(class="flex items-center justify-between") h2(class="text-xl font-bold") Пользовательский заголовок custom-close-button(@click="$emit('close')") template([body]) p Содержимое модального окна ``` ### `[footer]` (опциональный) - **Описание:** Нижняя область модального окна (обычно для кнопок) - **Пример:** ```pug modal-window(:is-visible="showModal") template([body]) p Вы уверены, что хотите удалить этот элемент? template([footer]) div(class="flex justify-end space-x-3") button(@click="$emit('close')" class="btn-secondary") Отмена button(@click="$emit('confirm')" class="btn-danger") Удалить ``` ## Размеры модальных окон ### Доступные размеры ```pug //- Маленькое (sm) modal-window(:is-visible="showModal" size="sm") //- Среднее (md) - по умолчанию modal-window(:is-visible="showModal" size="md") //- Большое (lg) modal-window(:is-visible="showModal" size="lg") //- Очень большое (xl) modal-window(:is-visible="showModal" size="xl") //- На весь экран (full) modal-window(:is-visible="showModal" size="full") ``` ## Стили и CSS классы ### Базовые классы - `.modal-overlay` - класс подложки - `.modal-container` - класс контейнера - `.modal-content` - класс контента ### Модификаторы размера - `.modal--sm` - маленький размер - `.modal--md` - средний размер (по умолчанию) - `.modal--lg` - большой размер - `.modal--xl` - очень большой размер - `.modal--full` - на весь экран ### Состояния анимации - `.modal-enter-active` - анимация появления - `.modal-leave-active` - анимация исчезновения ## Примеры использования в различных сценариях ### 1. Простая информационная модалка ```pug modal-window( :is-visible="showInfoModal" @close="showInfoModal = false" title="Информация" ) template([body]) p(class="mb-4") Это информационное модальное окно с простым текстом. p Вы можете закрыть его, нажав на крестик или кликнув вне окна. ``` ### 2. Модалка подтверждения действия ```pug modal-window( :is-visible="showConfirmModal" @close="showConfirmModal = false" @confirm="handleDeleteConfirm" title="Подтверждение удаления" size="sm" ) template([body]) p Вы уверены, что хотите удалить "{{ itemName }}"? Это действие нельзя отменить. template([footer]) div(class="flex justify-end space-x-3") button( @click="$emit('close')" class="px-4 py-2 text-gray-600 hover:text-gray-800 transition-colors" ) Отмена button( @click="$emit('confirm')" class="px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700 transition-colors" ) Удалить ``` ### 3. Форма в модальном окне ```pug modal-window( :is-visible="showFormModal" @close="closeFormModal" title="Добавить мероприятие" size="lg" :close-on-backdrop="false" ) template([body]) form(@submit.prevent="submitEventForm") div(class="space-y-4") div label(for="title" class="block text-sm font-medium text-gray-700") Название input( id="title" v-model="form.title" type="text" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500" required ) div label(for="description" class="block text-sm font-medium text-gray-700") Описание textarea( id="description" v-model="form.description" rows="4" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500" ) template([footer]) div(class="flex justify-end space-x-3") button( type="button" @click="$emit('close')" class="px-4 py-2 text-gray-600 hover:text-gray-800 transition-colors" ) Отмена button( type="submit" class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors" ) Сохранить ``` ### 4. Модалка с кастомным заголовком ```pug modal-window( :is-visible="showCustomModal" @close="showCustomModal = false" :show-close-button="false" ) template([header]) div(class="bg-gradient-to-r from-blue-500 to-purple-600 text-white p-6") div(class="flex items-center justify-between") div h2(class="text-2xl font-bold") Премиум функции p(class="text-blue-100") Доступно только для премиум пользователей button( @click="$emit('close')" class="text-white hover:text-blue-200 transition-colors" ) icon(name="close" class="w-6 h-6") template([body]) div(class="p-6") ul(class="space-y-3") li(class="flex items-center") icon(name="check" class="w-5 h-5 text-green-500 mr-3") span Расширенная аналитика li(class="flex items-center") icon(name="check" class="w-5 h-5 text-green-500 mr-3") span Приоритетная поддержка li(class="flex items-center") icon(name="check" class="w-5 h-5 text-green-500 mr-3") span Кастомные домены template([footer]) div(class="bg-gray-50 px-6 py-4 flex justify-between items-center") span(class="text-gray-600") Всего 999 TJS/месяц button( @click="subscribePremium" class="px-6 py-2 bg-gradient-to-r from-blue-500 to-purple-600 text-white rounded-lg hover:from-blue-600 hover:to-purple-700 transition-colors" ) Подписаться ``` ### 5. Модалка с загрузкой контента ```pug modal-window( :is-visible="showLoadingModal" @close="cancelLoading" title="Загрузка" :close-on-escape="false" :close-on-backdrop="false" :show-close-button="false" ) template([body]) div(class="text-center py-8") div(class="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4") p Загрузка данных, пожалуйста подождите... ``` ### 6. Модалка с вкладками ```pug modal-window( :is-visible="showTabsModal" @close="showTabsModal = false" title="Настройки" size="lg" ) template([body]) div div(class="border-b border-gray-200") nav(class="-mb-px flex space-x-8") button( v-for="tab in tabs" :key="tab.id" @click="currentTab = tab.id" :class="{ 'border-blue-500 text-blue-600': currentTab === tab.id, 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300': currentTab !== tab.id }" class="whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm" ) {{ tab.name }} div(class="py-4") div(v-if="currentTab === 'general'") h3(class="text-lg font-medium mb-4") Основные настройки //- Контент вкладки div(v-else-if="currentTab === 'security'") h3(class="text-lg font-medium mb-4") Безопасность //- Контент вкладки ``` ## Управление через глобальную шину событий ### Открытие модального окна ```coffee # В любом компоненте EventBus.emit('open_modal', { component: require('app/components/CustomModal'), props: { title: 'Кастомное окно', data: someData } }) ``` ### Закрытие модального окна ```coffee # Закрытие текущего модального окна EventBus.emit('close_modal') # Закрытие всех модальных окон EventBus.emit('close_all_modals') ``` ## Интеграция с глобальным состоянием ### Использование с appState ```coffee # В основном приложении appState: modalState: isVisible: false component: null props: {} # Открытие модалки openModal: (component, props = {}) -> @appState.modalState.component = component @appState.modalState.props = props @appState.modalState.isVisible = true # В шаблоне modal-window( :is-visible="appState.modalState.isVisible" @close="closeModal" v-if="appState.modalState.component" ) component( :is="appState.modalState.component" v-bind="appState.modalState.props" @close="closeModal" ) ``` ## Анимации и переходы ### Кастомные анимации ```styl // В стилях компонента .modal-custom-enter-active transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) .modal-container transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) transform: scale(0.95) translateY(-10px) opacity: 0 .modal-custom-enter-to .modal-container transform: scale(1) translateY(0) opacity: 1 ``` ## Best Practices ### 1. Управление состоянием ```coffee # Правильно - реактивное управление data: -> return showModal: false methods: openModal: -> @showModal = true closeModal: -> @showModal = false ``` ### 2. Обработка подтверждений ```coffee methods: handleConfirm: -> try await this.performAction() this.showModal = false this.showSuccessMessage() catch error this.showErrorMessage(error) ``` ### 3. Доступность ```pug //- Добавляйте aria-атрибуты для доступности modal-window( :is-visible="showModal" @close="closeModal" role="dialog" aria-labelledby="modal-title" ) template([header]) h2(id="modal-title") Заголовок модалки ``` ### 4. Управление фокусом ```coffee # Автоматически фокусироваться на первом интерактивном элементе mounted: -> this.$nextTick(() -> const firstInput = this.$el.querySelector('input, button, textarea') if firstInput firstInput.focus() ) ``` ## Отладка и разработка ### Логирование событий ```coffee # Отслеживание событий модального окна EventBus.on('modal_opened', (data) -> debug.log "Модальное окно открыто: "+data.component?.name ) EventBus.on('modal_closed', (data) -> debug.log "Модальное окно закрыто" ) ``` ### Проверка доступности ```coffee # Проверка управления фокусом checkFocusManagement: -> if this.isVisible const activeElement = document.activeElement const modalContent = this.$el.querySelector('.modal-content') if modalContent and !modalContent.contains(activeElement) debug.log "Фокус вне модального окна!" ``` Компонент ModalWindow предоставляет мощный и гибкий инструмент для создания модальных окон с поддержкой анимаций, управления через события, кастомизацией и соблюдением лучших практик доступности.