Все о работе модальных окон в проекте
Регистрация модального окна
Расположение модальных окон
js
.
└─ src/
└─ components/
└─ Modals/
├─ ConfirmDelete/
├─ UnsavedChanges/
└─ YourNewModal/Дополнительно
Важно называть будущую директорию модального окна в стиле CamelCase.
Минимальная вложенность директории модального окна
YourNewModal
├─ index.ts
├─ index.vue
├─ Loader.vue
└─ types.tsВажно
index.ts - Это главная точка входа в эту директориюindex.vue - Само модальное окно с контентомLoader.vue - Лоадер модального окнаtypes.ts - Все используемые типы в контексте этого модального окна
Минимальная вложенность кода в каждом файле
Дополнительно
Данный код является не обязательным и может быть изменен по усмотрению разработчика
ts
import { default as Component } from './index.vue';
export * from './types';
export default Component;ts
export interface IThe[`MyNewModalName`]ModalProps {
// Здесь пишем пропсы, которые хотим принимать
}
export interface IThe[`MyNewModalName`]ModalEmits {
(event: 'close'): void
// Здесь пишем emit's, которые хотим принимать
}vue
<template>
<TheModal :id="id" title="Мое новое модальное окно"> <!-- Этот id(props) - мы получаем всегда -->
<template #content>
<!-- Тут наш будущий главный контент -->
</template>
<template #footer>
<!-- Тут наш будущий контент футера -->
</template>
</TheModal>
</template>
<script async setup lang="ts">
// Types
import type { IModalDefaultProps } from "@/services/Modals";
import type { IThe[`MyNewModalName`]ModalEmits, IThe[`MyNewModalName`]ModalProps } from "./";
type ExtendedPropsT = IModalDefaultProps & IThe[`MyNewModalName`]ModalProps
// Modules
import { defineEmits, defineProps } from "vue";
// Components
import TheModal from "@/components/ui/TheModal";
// Inits
const props = defineProps<ExtendedPropsT>();
const emits = defineEmits<ITheConfirmDeleteModalEmits>();
</script>
<style scoped lang="scss">
@reference "tailwindcss/theme";
// Наши будущие стили модального окна
</style>vue
<template>
<!-- Тут пример использование skeleton -->
<TheModal :id="id">
<template #content>
<div class="flex flex-col items-center justify-center py-5">
<Skeletor class="mb-10" width="80" height="80" circle />
<Skeletor height="20" width="100%" class="rounded-md mb-3 min-w-80" />
<Skeletor height="20" width="100%" class="rounded-md mb-3" />
<Skeletor height="20" width="100%" class="rounded-md" />
</div>
</template>
<template #footer>
<div class="flex justify-end gap-4">
<Skeletor height="48" width="89" class="rounded-md" />
<Skeletor height="48" width="89" class="rounded-md" />
</div>
</template>
</TheModal>
</template>
<script setup lang="ts">
// Types
import type { IModalDefaultProps } from "@/services/Modals";
import type { IThe[`MyNewModalName`]ModalEmits, IThe[`MyNewModalName`]ModalProps } from "./";
type ExtendedPropsT = IModalDefaultProps & IThe[`MyNewModalName`]ModalProps
// Modules
import { defineProps, defineEmits } from 'vue';
// Components
import TheModal from "@/components/ui/TheModal";
import { Skeletor } from 'vue-skeletor';
// Inits
defineProps<ExtendedPropsT>();
defineEmits<IThe[`MyNewModalName`]ModalEmits>();
</script>Добавление нового модального окна в словарь
ts
// Файл расположен по: ./src/components/Modals/index.ts
// Other
modals.set('myNewModal', {
content: defineAsyncComponent(() => import('@/components/Modals/MyNewModal')),
loader: (await import('@/components/Modals/MyNewModal/Loader.vue')).default,
title: 'Заголовок нового модального окна'
}); Регистрация props и emit's в логику сервиса модальных окон
ts
// Файл расположен по: ./src/services/Modals/types.ts
import type {
IThe[`MyNewModalName`]ModalProps,
IThe[`MyNewModalName`]ModalEmits
} from "@/components/Modals/MyNewModal";
/**
* Тип, который отображает имена модальных окон на их соответствующие свойства.
* Каждое имя модального окна соответствует конкретным параметрам, которые оно принимает.
*/
export type ModalsPropsMap = {
'unsavedChanges': ITheUnsavedChangesModalProps,
'confirmDelete': ITheConfirmDeleteModalProps,
'myNewModal': IThe[`MyNewModalName`]ModalProps, // ВАЖНО: названия поля должен быть одинаковым как в названии словаря
}
/**
* Тип, который отображает имена модальных окон на их соответствующие события.
* Каждое имя модального окна соответствует конкретным параметрам, которые оно принимает.
*/
export type ModalsEmitsMap = {
'unsavedChanges': ITheUnsavedChangesModalEmits,
'confirmDelete': ITheConfirmDeleteModalEmits,
'myNewModal': IThe[`MyNewModalName`]ModalEmits, // ВАЖНО: названия поля должен быть одинаковым как в названии словаря
}Вызов и использование
То как вызывается
ts
// Modules
import ModalsService from '@/services/Modals';
// Inits
const modalsService = new ModalsService();
// Scenario
modalsService.addModal<'myNewModalName'>({
name: 'myNewModalName',
props: {
// Это пример отправлямого пропса.
// Он блокирует закрытие модалки фоном.
isProhibitBackClose: true,
},
emits: {
submit: () => {}
}
});Совет
В данном случае generic нужен, чтобы при отправке props или emit's сразу определялся тип данных, которых можно отправить
Изменение входных props модального окна
ts
// Modules
import ModalsService from '@/services/Modals';
// Inits
const modalsService = new ModalsService();
// Scenario
// В данном случае modal.id мы принимаем props'ом
// из родителя и переотравляем его.
modalsService.addPropsInModal<'myNewModalName'>(modal.id, {
firstName: 'he-he',
lastName: 'ha-ha'
});