vue3 自定义函数之点击页面其他地方下拉框消失

205 阅读1分钟

实现的功能: 点击页面其他地方下拉框消失;

技术栈: vue3+ts

思路: 判断点击的地方是否包含下拉框元素,包含不做处理,不包含且下拉框是展开状态就收起下拉框

dropdown.vue

<template>
  <div class="dropdown" ref="dropdownRef">
    <a
      class="btn btn-secondary dropdown-toggle"
      href="#"
      role="button"
      data-bs-toggle="dropdown"
      @click.prevent="handleOpen"
    >
      {{ props.title }}
    </a>

    <ul class="dropdown-menu" style="display: block" v-if="isOpen">
         <li>新建文章</li>
         <li>编辑资料</li>
         <li>退出登录</li>
    </ul>
  </div>
</template>
<script setup lang="ts">
import { defineProps, ref, watch } from 'vue'
import useClickOutside from '@/hooks/useClickOutside'
const props = defineProps({
  title: {
    type: String,
    required: true
  }
})
const isOpen = ref(false)
const handleOpen = () => {
  isOpen.value = !isOpen.value
  console.log(isOpen.value)
}
const dropdownRef = ref<null | HTMLElement>(null) // ref元素
const isClickOutside = useClickOutside(dropdownRef)
// watch 监听是否点击页面其他地方
watch(isClickOutside, () => {
  if (isOpen.value && isClickOutside.value) {
    isOpen.value = false
  }
  console.log(isOpen.value)
})
</script>

useClickOutside.ts

import { ref, onMounted, onUnmounted, Ref } from 'vue'
//Ref 获取ref元素
const useClickOutside = (elementRef: Ref<null | HTMLElement>) => {
  const isClickOutside = ref(false)
  const handler = (e: MouseEvent) => {
    if (!elementRef.value?.contains(e.target as HTMLElement)) {
      isClickOutside.value = true
    } else {
      isClickOutside.value = false
    }
  }
  onMounted(() => {
    document.addEventListener('click', handler)
  })
  onUnmounted(() => {
    document.removeEventListener('click', handler)
  })
  return isClickOutside
}

export default useClickOutside