Я использую компонент HeadlessUI/Vue в своем приложении Nuxt 3 для создания диалоговых окон/модальных окон. Я использую последнюю версию "@headlessui/vue": "^1.7.22" и разрабатываю последнюю версию браузера Chrome.
Я создаю DialogPanel1.vue, используя headlessui/vue. У меня есть кнопка DialogPanel1.vue, при нажатии на нее я открываю DialogPanel2.vue, но внутри DialogPanel2.vue, когда я нажимаю где-нибудь, она автоматически закрывает DialogPanel1.vue, которая находится за DialogPanel2.vue.
Репозиторий с минимальным воспроизведением в CodeSandBox
Почему он закрывается DialogPanel1 автоматически? Я хочу, чтобы DialogPanel1 закрывался только тогда, когда я нажимаю кнопку закрытия в DialogPanel1.vue, а не при каждом нажатии DialogPanel2. Я попробовал добавить @click.stop или @mousedown.stop, чтобы предотвратить распространение события, но это все равно не работает. Может кто-нибудь, пожалуйста, дайте мне знать о проблеме?
Ниже приведен мой полный код /pages/index.vue:
<template>
<DialogPanel1 />
</template>
<script setup>
</script>
Ниже приведены мои компоненты /component/DialogPanel1.vue:
<template>
<div class = "mb-2">
<button
type = "button"
@click = "openModal1"
class = "flex secondary-button text-secondary dark:bg-transparent dark:hover:text-secondary dark:hover:bg-slate-700 mx-auto justify-center items-center rounded border focus:ring-0 focus:outline-none font-medium px-5 py-2.5 text-center min-w-[8rem] sm:min-w-[10rem] lg:min-w-[12rem]"
>
<span class = "pr-1"> Open Modal-1 </span>
</button>
</div>
<TransitionRoot appear :show = "modal1" as = "template">
<Dialog as = "div" @close = "closeModal" class = "relative z-30">
<div class = "fixed inset-0 overflow-y-auto">
<div
class = "flex min-h-full items-center justify-center p-4 text-center"
>
<DialogPanel
class = "dark:bg-slate-800 w-full transform overflow-auto rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all z-20"
>
THIS IS MODAL-1
<button
class = "flex secondary-button text-secondary dark:bg-transparent dark:hover:text-secondary dark:hover:bg-slate-700 mx-auto justify-center items-center rounded border focus:ring-0 focus:outline-none font-medium px-5 py-2.5 text-center min-w-[8rem] sm:min-w-[10rem] lg:min-w-[12rem]"
@click = "openModal2"
>
MODAL-2
</button>
</DialogPanel>
</div>
</div>
</Dialog>
</TransitionRoot>
<DialogPanel2 :modal2 = "modal2" @closeModal = "hideModal2" />
</template>
<script setup>
import { TransitionRoot, Dialog, DialogPanel } from "@headlessui/vue";
const modal1 = ref(false);
const modal2 = ref(false);
//Function to open Modal-1
const openModal1 = () => {
console.info("Opening Modal-1");
modal1.value = true;
};
//Close the modal on click of the button
const closeModal = () => {
console.info("CLOSE MODAL-1");
modal1.value = false;
};
//Function to open Modal-2
const openModal2 = () => {
console.info("Open MODAL-2");
modal2.value = true;
};
const hideModal2 = () => {
console.info("Closing MODAL-2");
modal2.value = false;
};
</script>
Ниже мой /components/DialogPanel2.vue:
<template>
<TransitionRoot
appear
:show = "modal2"
as = "template"
@close = "closeModal"
@click.native.stop.prevent
>
<Dialog
:initialFocus = "focusRef"
as = "div"
@click.native.stop.prevent
class = "relative z-50"
>
<div class = "fixed inset-0 overflow-y-auto">
<div
class = "flex min-h-full items-center justify-center p-4 text-center"
>
<DialogPanel
@click.native.stop.prevent
class = "pt-5 w-full max-w-xl overflow-y-auto transform overflow-visible rounded-2xl bg-white dark:bg-slate-800 p-6 align-middle shadow-xl transition-all"
>
THIS IS MODAL-2
<span class = "text-black dark:text-white">Field-1</span>
<input
ref = "focusRef"
v-model = "test.one"
type = "text"
class = "relative w-full h-full bg-gray-50 dark:text-black dark:bg-gray-700 dark:border-gray-600 border-gray-300 border rounded text-center block overflow-hidden"
/>
<span class = "text-black dark:text-white">Field-2</span>
<input
v-model = "test.two"
type = "text"
class = "relative w-full h-full bg-gray-50 dark:text-white dark:bg-gray-700 dark:border-gray-600 border-gray-300 border rounded text-center block overflow-hidden"
/>
<button class = "mt-4" @click = "closeModal">Close</button>
</DialogPanel>
</div>
</div>
</Dialog>
</TransitionRoot>
</template>
<script setup>
import { TransitionRoot, Dialog, DialogPanel } from "@headlessui/vue";
const props = defineProps({
modal2: {
type: Boolean, //Show/hide the modal based on the flag
required: false,
},
});
const emits = defineEmits(["closeModal"]);
const focusRef = ref(null);
//Reference variables
const modal2 = ref(props.modal2);
const test = ref({});
watch(
() => props.modal2,
async (newValue) => {
modal2.value = newValue;
}
);
const closeModal = () => {
console.info("CLOSE MODAL-2");
modal2.value = false;
emits("closeModal");
};
</script>
Почему нажатие на DialogPanel2.vue автоматически закрывает предыдущее диалоговое окно DialogPanel1.vue? Я попытался удалить @close = "closeModal" из DialogPanel1.vue, что предотвратило бы закрытие DialogPanel1.vue, но из-за этого я не могу редактировать ни одно из полей в DialogPanel2.vue, что означает, что фокус все еще остается на DialogPanel1.vue, из-за чего я не могу получить доступ или фокус в DialogPanel2.vue. Следующие изменения в DialogPanel1.vue:
<TransitionRoot appear :show = "modal1" as = "template">, но после этого я не могу получить доступ к полям ввода в DialogPanel2.vue.
Я до сих пор не могу определить основную причину и устранить ее, любые предложения будут очень полезны.
Проблема: Коды и песочница
Следующая проблема моя проблема GIF:





Я не могу прочитать полный код, но кажется, что в диалоговом окне используется что-то вроде «внешнего щелчка», который будет рассматривать любой щелчок, который не находится внутри элемента или его дочернего элемента, как «внешний щелчок» и запускает функцию закрытия. В вашем случае ваш <DialogPanel2> находится за пределами <DialogPanel1>, поэтому, когда <DialogPanel1> открывается и <DialogPanel2> также открывается, все, что не является дочерним элементом <DialogPanel1>, будет рассматриваться как находящееся за его пределами (в этом случае <DialogPanel2> считается за пределами <DialogPanel1>), таким образом, щелчок приведет к закрытию <DialogPanel1>.
Самое простое решение (в зависимости от вашего варианта использования) — переместить <DialogPanel2> внутрь <DialogPanel1>, чтобы он не считался внешним щелчком, например:
<TransitionRoot appear :show = "modal1" as = "template" @close = "closeModal">
<Dialog as = "div" class = "relative z-30">
<div class = "fixed inset-0 overflow-y-auto">
<div
class = "flex min-h-full items-center justify-center p-4 text-center"
>
<DialogPanel
class = "dark:bg-slate-800 w-full transform overflow-auto rounded-2xl bg-gray-200 p-6 text-left align-middle shadow-xl transition-all z-20"
>
THIS IS MODAL-1
<button
class = "flex secondary-button text-secondary dark:bg-transparent dark:hover:text-secondary dark:hover:bg-slate-700 mx-auto justify-center items-center rounded border focus:ring-0 focus:outline-none font-medium px-5 py-2.5 text-center min-w-[8rem] sm:min-w-[10rem] lg:min-w-[12rem]"
@click = "openModal2"
>
MODAL-2
</button>
<DialogPanel2 :modal2 = "modal2" @closeModal = "hideModal2" /><!-- move it here-->
</DialogPanel>
</div>
</div>
</Dialog>
</TransitionRoot>
Большое спасибо за ответ. Вы правы, это из-за мелочи, где я разместил его снаружи. Мне потребовались дни, чтобы понять это. Большое спасибо за ответ и теперь все работает так, как ожидалось.