From 01929c4b30e72fdd039ef580625e415011311cc4 Mon Sep 17 00:00:00 2001 From: seorang42 Date: Tue, 4 Feb 2025 15:51:28 +0900 Subject: [PATCH] =?UTF-8?q?:sparkles:=20[feat]=20:=20useOutsideClick=20?= =?UTF-8?q?=EC=BB=A4=EC=8A=A4=ED=85=80=20=ED=9B=85=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/filters/FilterCategory.vue | 6 ++++++ src/components/filters/FilterDropdown.vue | 4 ++++ .../filters/FilterDropdownMulti.vue | 4 ++++ src/components/hooks/useOutsideClick.ts | 19 +++++++++++++++++++ 4 files changed, 33 insertions(+) create mode 100644 src/components/hooks/useOutsideClick.ts diff --git a/src/components/filters/FilterCategory.vue b/src/components/filters/FilterCategory.vue index acb7c27d..c9aadf57 100644 --- a/src/components/filters/FilterCategory.vue +++ b/src/components/filters/FilterCategory.vue @@ -3,6 +3,7 @@
1차 카테고리
선택 @@ -31,6 +32,7 @@
2차 카테고리
@@ -77,6 +79,7 @@ import { dropdownIcon } from '@/constants/iconPath' import type { Category, FilterCategoryProps } from '@/types/common' import { computed, ref, watchEffect } from 'vue' import CommonIcons from '../common/CommonIcons.vue' +import { useOutsideClick } from '../hooks/useOutsideClick' const { categoryList = [], main, sub } = defineProps() const emit = defineEmits(['update:main', 'update:sub']) @@ -121,4 +124,7 @@ const onMainClick = (category: Category) => { const onSubClick = (value: number) => { emit('update:sub', value) } + +const { htmlRef: mainRef } = useOutsideClick(() => isMainOpened.value && toggleDropdown('main')) +const { htmlRef: subRef } = useOutsideClick(() => isSubOpened.value && toggleDropdown('sub')) diff --git a/src/components/filters/FilterDropdown.vue b/src/components/filters/FilterDropdown.vue index 2f833376..85ef31d6 100644 --- a/src/components/filters/FilterDropdown.vue +++ b/src/components/filters/FilterDropdown.vue @@ -5,6 +5,7 @@ :class="width === 'full' && 'grow'"> {{ title }}
{{ @@ -32,6 +33,7 @@ import type { Filter } from '@/types/common' import { ref } from 'vue' import { dropdownIcon } from '@/constants/iconPath' import CommonIcons from '../common/CommonIcons.vue' +import { useOutsideClick } from '../hooks/useOutsideClick' const { title, value, width = '120', optionList } = defineProps() const emit = defineEmits(['update:value']) @@ -43,4 +45,6 @@ const onOptionClick = (option: string) => { emit('update:value', option) toggleDropdown() } + +const { htmlRef } = useOutsideClick(() => isDropdownOpened.value && toggleDropdown()) diff --git a/src/components/filters/FilterDropdownMulti.vue b/src/components/filters/FilterDropdownMulti.vue index 10c923a9..d828c2d9 100644 --- a/src/components/filters/FilterDropdownMulti.vue +++ b/src/components/filters/FilterDropdownMulti.vue @@ -5,6 +5,7 @@ :class="width === 'full' && 'grow'"> {{ title }}
선택 @@ -35,6 +36,7 @@ import type { Filter } from '@/types/common' import { ref } from 'vue' import { dropdownIcon } from '@/constants/iconPath' import CommonIcons from '../common/CommonIcons.vue' +import { useOutsideClick } from '../hooks/useOutsideClick' const { title, width = '120', optionList, value } = defineProps() const emit = defineEmits(['update:value']) @@ -45,4 +47,6 @@ const toggleDropdown = () => (isDropdownOpened.value = !isDropdownOpened.value) const onOptionClick = (option: string | number) => { emit('update:value', option) } + +const { htmlRef } = useOutsideClick(toggleDropdown) diff --git a/src/components/hooks/useOutsideClick.ts b/src/components/hooks/useOutsideClick.ts new file mode 100644 index 00000000..da18a64d --- /dev/null +++ b/src/components/hooks/useOutsideClick.ts @@ -0,0 +1,19 @@ +import { onMounted, onUnmounted, ref } from 'vue' + +export const useOutsideClick = (onClick: () => void) => { + const htmlRef = ref(null) + + const onOutsideClick = (event: MouseEvent) => { + if (htmlRef.value && !htmlRef.value.contains(event.target as Node)) { + onClick() + } + } + + onMounted(() => { + window.addEventListener('click', onOutsideClick) + }) + onUnmounted(() => { + window.removeEventListener('click', onOutsideClick) + }) + return { htmlRef } +}