
Модальные диалоги не такая и сложная задача в разработке. Разве что можно легко запутаться в коде, если нужно вызывать модальные окна по цепочке. Но это очень монотонная и неинтересная работа с повторяющейся логикой, которую подчас копируют из компонента в компонет с незначительными изменениями.
Хорошим решением было бы создать функцию, которая принимала бы компонент диалога и управляла бы его рендерингом в шаблоне, а этот диалог можно «промисифицировать» и работать с ним как с асинхронной функцией. Как например в этой библиотеке vue-modal-dialogs. К сожалению она давно не обновлялась и не опддерживает Vue 3.
А еще отличной идеей для организации кода было бы отдельные хуки, код в которых выполнялся бы в зависимости от действий пользователя.
Все это есть в плагине vuejs-confirm-dialog, о котором я хочу вам рассказать.
Конечный результат можно посмотреть в песочнице. Код немного отличается от того, что в посте.
Установка
Начнем с создания нового проекта на Vue 3. Введем в консоли:
vue create dialogs-guide // Pick a second option ? Please pick a preset: Default ([Vue 2] babel, eslint) > Default (Vue 3) ([Vue 3] babel, eslint) Manually select features
Мы получили стандартный шаблон нового проекта. Далее установим библиотеку согласно документации в README.md.
npm i vuejs-confirm-dialog
Заменим код в main.js на такой:
import { createApp } from 'vue' import App from './App.vue' import * as ConfirmDialog from 'vuejs-confirm-dialog' createApp(App).use(ConfirmDialog).mount('#app')
Использование
Теперь перейдем в файл App.vue. Первым делом исправим код шаблона. Для работы библиотеки нам обязательно нужно добавить в него компонент <DialogsWrapper /> и удалим HelloWord:
<template> <img alt="Vue logo" src="./assets/logo.png"> <DialogsWrapper /> </template>
Теперь изучим как использовать функцию createConfirmDialog. Используем новый синтаксис setup для раздела script. createConfirmDialog первым аргументом принимает компонент, который будет использоваться как модальное окно, а вторым входные данные для него. Функция возвращает обьект с методами для работы с модальным окном, так метод reveal вызывает диалог, а хук onConfirm принимает код, который выполниться если пользователь нажмет на «согласен». Можно заставить появляться компонерт HelloWord при нажатии на лого и передать ему значение пропса msg:
// App.vue <template> <img alt="Vue logo" src="./assets/logo.png" @click="reveal"> <DialogsWrapper /> </template> <script setup> import HelloWorld from './components/HelloWorld.vue' import { createConfirmDialog } from 'vuejs-confirm-dialog' const { reveal } = createConfirmDialog(HelloWorld, { msg: 'Hi!'}) </script>
Никакой дополнительной логики не требуется. Компонент отрисовывается после вызова функции reveal и исчезает после того, как пользователь отреагирует на диалог.
Реальный пример компонента
Теперь напишем что-то более приближенное к реальному использованию.
Создадим новый компонент SimpleDialog.vue в папке components:
<template> <div class="modal-container"> <div class="modal-body"> <span class="modal-close" @click="emit('cancel')">?</span> <h2>{{ question }}</h2> <div class="modal-action"> <button class="modal-button" @click="emit('confirm')">Confirm</button> <button class="modal-button" @click="emit('cancel')">Cancel</button> </div> </div> </div> </template> <script setup> import { defineProps, defineEmits } from 'vue' const props = defineProps(['question']) const emit = defineEmits(['confirm', 'cancel']) </script> <style> .modal-container { display: flex; justify-content: center; align-items: center; position: absolute; top: 0; left: 0; right: 0; width: 100%; height: 100%; background-color: #cececeb5; } .modal-body { background-color: #fff; border: 2px solid #74a2cf; border-radius: 10px; text-align: center; padding: 20px 40px; min-width: 250px; display: flex; flex-direction: column; } .modal-action { display: flex; flex-direction: row; gap: 40px; justify-content: center; } .modal-button { cursor: pointer; height: 30px; padding: 0 25px; border: 2px solid #74a2cf; border-radius: 5px; background-color: #80b2e4; color: #fff; } .modal-close { cursor: pointer; position: relative; align-self: end; right: -33px; top: -17px; } </style>
Обратите внимание, что для полноценной работы нужно добавить два входящих события в модальный диалог: ['confirm', 'cancel'].
А теперь используем его для подтверждения какого-либо действия, например, чтобы спрятать логотип. Логику кода, который будет исполняться после согласия пользователя, поместим в коллбек хука onConfirm.
<template> <img v-show="showLogo" alt="Vue logo" src="./assets/logo.png"> <button @click="reveal">Hide Logo</button> <DialogsWrapper /> </template> <script setup> import SimpleDialog from './components/SimpleDialog.vue' import { createConfirmDialog } from 'vuejs-confirm-dialog' import { ref } from 'vue' const showLogo = ref(true) const { reveal, onConfirm } = createConfirmDialog(SimpleDialog, { question: 'Are you sure you want to hide the logo?'}) onConfirm(() => { showLogo.value = false }) </script>
Переиспользование
Что делать, если у нас есть много случаев, когда требуется подтверждение каких-либо действий? Не писать же каждый раз createConfirmDialog заново?
Можно написать функцию, которая автоматизирует этот процесс для нас.
// src/composables/useConfirmBeforeAction.js import SimpleDialog from './../components/SimpleDialog' import { createConfirmDialog } from 'vuejs-confirm-dialog' const useConfirmBeforeAction = (action, props) => { const { reveal, onConfirm } = createConfirmDialog(SimpleDialog, props) onConfirm(action) reveal() } export default useConfirmBeforeAction
Теперь используем ее для подтверждения перехода по внешним ссылкам:
// App.vue <template> <ul> <li v-for="(link, i) in LINKS" @click="goToLink(link)" :key="i"> {{ link }} </li> </ul> <DialogsWrapper /> </template> <script setup> import SimpleDialog from './components/SimpleDialog.vue' import { createConfirmDialog } from 'vuejs-confirm-dialog' import useConfirmBeforeAction from './composables/useConfirmBeforeAction' const LINKS = [ 'https://vuejs.org/', 'https://github.com/', 'https://vueuse.org/', ] const goToLink = (link) => { useConfirmBeforeAction( () => { window.location = link }, { question: `Do you want to go to ${link}?` } ) } </script>
Заключение
Функция createConfirmDialog позволяет упростить работу с модальными окнами, переиспользование логики и создание цепочек последовательных диалогов. Она берет на себе заботу о рендере модального окна, передачу входящих параметров в компонент и получении данныт от него. Она очень гибкая — ее очень легко подстроить под ваши нужды.
Это не все ее возможности. Например, если концеция хуков вам не близка, можно заменить их на работу с промисом, который возвращает функция reveal. И даже использовать её в Options API.
ссылка на оригинал статьи https://habr.com/ru/post/662652/
Добавить комментарий