this.$vs.confirm (Vuesax) как это работает?
Вопрос к знатокам Vue, у фрэймворка Vuesax для Vue, есть функция this.$vs.confirm , которая вызывает модалку и при нажатии да, выполняет колбек который в нее передается.
Вопрос в том, как можно реализовать что нибудь подобное самому?
Ответы (1 шт):
Суть данной методы не является специфичной для vue.
Накрыть страницу div-ом (или любым другим элементом, каким только сможете:).
Посреди этого div-а нарисовать свой диалог.
div как бы лишает пользователя доступа к странице под ним, за счёт чего достигается модальность. Хотя этого не достаточно, поэтому "как бы".
Для реализации данной задумки в/на vue можно поступить следующим образом:
Создаём plugin в папке src/plugins/ConfirmDialog
Внутри создаём:
Компонент vue, который представляет окошко диалога
plugins/ConfirmDialog/ConfirmDialog.vue<template> <div class="confirm-dialog-container"> <div class="configm-dialog"> <div class="header">{{ header }}</div> <div class="message">{{ message }}</div> <div class="buttons"> <button @click="$emit('input', true)">Да</button> <button @click="$emit('input', false)">Нет</button> </div> </div> </div> </template> <script> export default { name: 'ConfirmDialog', props: { header: String, message: String, } } </script> <style> .confirm-dialog-container { position: fixed; top: 0; right: 0; bottom: 0; left: 0; display: flex; justify-content: center; align-items: center; background:rgba(0, 0, 0, 0.53) } .confirm-dialog-container .configm-dialog { min-width: 300px; background-color: white; border-color: black; border-style: solid; border-width: thin; } .confirm-dialog-container .configm-dialog .header { padding: 10px; font-weight: bold; } .confirm-dialog-container .configm-dialog .message { padding: 40px; } .confirm-dialog-container .configm-dialog .buttons { padding: 15px; background-color: lightgray; text-align: right; } .confirm-dialog-container .configm-dialog .buttons button:nth-child(2) { margin-left: 15px; } </style>
С помощью стилей добиваемся того, чтобы контейнер диалога confirm-dialog-container полностью накрыл body страницы.
Собственно сам plugin
plugins/ConfirmDialog/index.jsimport Vue from 'vue' import ConfirmDialog from './ConfirmDialog.vue' export default { install(vue) { const root = new Vue({ data() { return { visible: false, header: '', message: '', callback: null, } }, methods: { onConfirmInput(event) { this.visible = false; if (this.callback) { this.$nextTick(() => { this.callback(event) }); } } }, components: { ConfirmDialog }, render(h) { return h('div', {}, this.visible ? [ h(ConfirmDialog, { props: { header: this.header, message: this.message, }, on: { input: this.onConfirmInput, }}) ] : []) }, }); vue.confirm = function(header, message, callback) { root.header = header; root.message = message; root.callback = callback; root.visible = true; }; root.$mount(document.body.appendChild(document.createElement('div'))); } }
Плугин создаёт компонент root, который содержит ConfirmDialog.vue и обрабатывает события нажатия его кнопок, управляет его свойствами (заголовок, сообщение).
На странице создаётся элемент div, в который монтируется этот root.
Таким образом на странице создаётся ещё одно vue-приложение. root его корневой компонент, поэтому root:)
А в целевое приложение, добавляется метод confirm, предназначенный для вывода диалога.
Для активации/деактивации диалога используется свойство visible root. См. его метод render(h)
Теперь подключение и использование
Подключить plugin в главное приложение
main.jsimport ConfirmDialog from './plugins/ConfirmDialog' Vue.use(ConfirmDialog);Использование
components/MyComponent.vueVue.confirm('Требуется подтверждение!', 'Вы согласны?', (confirmed) => { if (confirmed) { // да ... } else { // нет ... } });
На самом деле это только создаёт видимость модальности.
Очень сложно сделать по-настоящему модальное окошко.
Например, нажимая tab, пользователь может легко переместить фокус под диалог.
Нужно предпринимать специальные меры против побега из модального окошка.