Использование Modal из безголового пользовательского интерфейса в vue3
Я хочу использовать модальный интерфейс без заголовка в vue3, но проблема в том, что я не понимаю, как я могу переключить модальное окно с родительского (App.vue), если модальное окно является компонентом.
Я попытался передать опору в Modal.vue, но она не работает. Моя стратегия заключалась в том, чтобы использовать опору modalActive, посмотреть ее и вызвать соответствующую функцию для переключения модального окна, но она просто не работает.
В примере с пользовательским интерфейсом без головы используется кнопка, но она находится внутри самого компонента, поэтому очевидно, что он может без проблем получить доступ к функциям этого компонента.
Мой код:
App.vue
<template>
<Modal>
<template v-slot:default>
<LoginForm />
</template>
</Modal>
</template>
<script setup lang="ts">
import Modal from './components/Modal.vue';
import LoginForm from './components/LoginForm.vue';
import { ref } from 'vue';
</script>
Modal.vue
<template>
<TransitionRoot appear :show="isOpen" as="template">
<Dialog as="div" @close="closeModal">
<div class="fixed inset-0 z-10 overflow-y-auto">
<div class="min-h-screen px-4 text-center">
<TransitionChild
as="template"
enter="duration-300 ease-out"
enter-from="opacity-0"
enter-to="opacity-100"
leave="duration-200 ease-in"
leave-from="opacity-100"
leave-to="opacity-0"
>
<DialogOverlay class="fixed inset-0" />
</TransitionChild>
<span class="inline-block h-screen align-middle" aria-hidden="true">​</span>
<TransitionChild
as="template"
enter="duration-300 ease-out"
enter-from="opacity-0 scale-95"
enter-to="opacity-100 scale-100"
leave="duration-200 ease-in"
leave-from="opacity-100 scale-100"
leave-to="opacity-0 scale-95"
>
<div
class="inline-block w-full max-w-md p-6 my-8 overflow-hidden text-left align-middle transition-all transform bg-white shadow-xl rounded-2xl"
>
<slot></slot> <!-- slot for forms -->
</div>
</TransitionChild>
</div>
</div>
</Dialog>
</TransitionRoot>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
import {
TransitionRoot,
TransitionChild,
Dialog,
DialogOverlay,
DialogTitle,
} from '@headlessui/vue'
const isOpen = ref(true)
function closeModal() {
isOpen.value = false
}
function openModal() {
isOpen.value = true
}
</script>
3 ответа
Вы должны использоватьвместе с
$refs
.
<script setup>
import { ref, watch, defineExpose } from 'vue'
...
const closeModal = function() {
isOpen.value = false
}
const openModal = function() {
isOpen.value = true
}
defineExpose({
openModal,
closeModal
})
</script>
Ссылка шаблона на ваш компонент:
<Modal ref="modal">
И метод
openModal
в приложении Vue:
components: {
Modal
},
methods: {
openModal() {
this.$refs.modal.openModal();
}
}
Вот рабочая версия: Vue SFC Playground
Вот важные части документации Vue 3 для понимания решения:
Ответ Tolbxela отлично работает, но если вы используете составной API, заключительная часть ответа будет выглядеть немного иначе.
const modal = ref(null)
//the variable name (modal) needs to match the template ref name
//given in the second step of Tolbxela's answer
const openModal = () => {
modal.value.openModal()
}
Спасибо за эти ответы, ребята - у меня была та же проблема (еще не специалист по композиции Vue, так как я только что пришел из Vue 2.x).
Если кому-то интересно, я закрыл свой диалог только при нажатии кнопки «закрыть» в самом диалоговом окне (а не клавиши esc или щелчка за пределами диалогового окна). Это делает модальное окно действительно «модальным».
<script setup>
import { ref, watch, onMounted, onUnmounted } from 'vue'
import {
TransitionRoot,
TransitionChild,
Dialog,
DialogPanel,
DialogTitle,
} from '@headlessui/vue'
const isOpen = ref(false)
function openModal(myEvent) {
isOpen.value = true
}
function closeModal(ev) {
if (typeof ev.target === 'undefined') return
if (ev.target.id !== 'closeDialogBtn') return // Give the 'close' button an id.
isOpen.value = false
}
onMounted(() => {
// block esc key from closing dialog.
document.addEventListener('keydown', makeDialogModal)
})
onUnmounted(() => {
// block esc key from closing dialog.
document.removeEventListener('keydown', makeDialogModal)
})
function makeDialogModal(e) {
if (e.key === 'Escape' || e.keyCode === 27) { // e.keyCode === 27 used for legacy
console.log('Escape key pressed')
e.stopPropagation()
return
}
}
defineExpose({
openModal,
closeModal
})
</script>