Подкомпонент Vue 3 вызывает событие щелчка при отображении

В vue 3 Compose API я показываю компонент всплывающего окна и хочу зафиксировать щелчок для закрытия модального окна.

мой код в родительском компоненте

<template>
<button @click = "toggleSettings" class = "bg-gray-300 text-gray-700 px-4 py-2 rounded flex items-center">
<span>⚙️</span>
</button>
<ModalSettings :visible = "showSettings" @onClose = "toggleSettings"/>
</template>

<script setup lang = "ts">
  import { ref } from 'vue'
  const showSettings = ref(false)
const toggleSettings = () => {
  showSettings.value = !showSettings.value
}
</script>

Код моего дочернего компонента

<template>
    <div  v-if = "visible" class = "fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
        <div ref = "customDiv" @click.stop class = "bg-white p-8 rounded-lg shadow-lg w-96">
            <h2 class = "text-xl font-bold mb-4"> Settings</h2>
        </div>
    </div>
</template>

<script setup lang = "ts">
import { ref, onMounted, onUnmounted, nextTick, defineProps } from 'vue'

const customDiv = ref<HTMLElement | null>(null)

const props = defineProps({
    visible: Boolean
})

onMounted(() => {
  nextTick(() => {  
    setTimeout(() => {
      document.addEventListener('click', handleClickOutside)
    }, 1000)
  })
})

onUnmounted(() => {
  document.removeEventListener("click", handleClickOutside)
})

const handleClickOutside = (event: MouseEvent) => {
  if (customDiv.value && !customDiv.value.contains(event.target)) {
    console.info('close the popup')
  }
}
</script>

Проблема в том, что каждый раз, когда я показываю модальный компонент, это как если бы щелчок немедленно (событие с моим хаком тайм-аута) вызывался за пределами модального компонента и поэтому он закрывал компонент (здесь, в примере, он просто пишет «закройте неожиданно возникнуть")

Знаете ли вы, что происходит и как это предотвратить?

Вам не следует использовать прослушиватели DOM vanilla JS при использовании Vue, особенно если для такого варианта использования есть специальное решение: vueuse.org/core/onClickOutside Он также удалит хаки timeOut + nextTick во что-то более чистое, IMO. .

kissu 02.06.2024 01:43

В противном случае, похоже, вот причина вашей проблемы: stackoverflow.com/a/35667286/8816585

kissu 02.06.2024 01:54
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
2
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы монтируете компонент сразу вместе с кнопкой, чтобы ваш обработчик событий начал действовать немедленно. Щелчок кнопки распространяется на документ, а затем обрабатывается модальным окном.

Решением грубой силы было бы добавить к кнопке модификатор stop:

@click.stop = "toggleSettings"

В противном случае добавьте/удалите прослушиватель при изменении visible (нужно setTimeout пропустить нажатие кнопки и добавить прослушиватель после него):

Смотрите на Vue SFC Playground

watch(() => props.visible, value => 
    setTimeout(() => document[`${value ? 'add' : 'remove'}EventListener`]('click', handleClickOutside)));

P.S. К сожалению, не удаляйте, обработчик также должен быть удален при размонтировании

onUnmounted(() => {
  document.removeEventListener("click", handleClickOutside)
})

Другие вопросы по теме