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 } +}