使用vue3 hook 完成一个点击元素外区域元素隐藏功能附加vue2自定义指令实现方式

一般这样的功能在一个项目中很多地方需要用到
vue3可以将功能代码单独提出来

import { ref, onMounted, onUnmounted, Ref } from 'vue'

const useClickOutside = (elementRef: Ref<null | HTMLElement>) => {
  const isClickOutside = ref(false)
  const handler = (e: MouseEvent) => {
    if (elementRef.value) {
      if (elementRef.value.contains(e.target as HTMLElement)) {
        isClickOutside.value = false
      } else {
        isClickOutside.value = true
      }
    }
  }
  onMounted(() => {
    document.addEventListener('click', handler)
  })
  onUnmounted(() => {
    document.removeEventListener('click', handler)
  })
  return isClickOutside
}

export default useClickOutside

在组件中使用

<div class="dropdown" ref="dropdownRef">
  <a href="#" class="btn btn-outline-light my-2 dropdown-toggle" @click.prevent="toggleOpen">
   点击title展示下拉
  </a>
  <ul class="dropdown-menu" :style="{display: 'block'}" v-if="isOpen">
    <li>下拉列表1</li>
    <li>下拉列表2</li>
    <li>下拉列表3</li>
    <li>下拉列表4</li>
  </ul>
</div>


<script lang="ts">
import { defineComponent, ref, watch } from 'vue'
import useClickOutside from '../hooks/useClickOutside'
export default defineComponent({
  name: 'Dropdown',
  props: {
    title: {
      type: String,
      required: true
    }
  },
  setup() {
    const isOpen = ref(false)
    const dropdownRef = ref<null | HTMLElement>(null)
    const toggleOpen = () => {
      isOpen.value = !isOpen.value
    }
    const isClickOutside = useClickOutside(dropdownRef)

    watch(isClickOutside, () => {
      if (isOpen.value && isClickOutside.value) {  //下拉展开且点击位置为组件外的区域隐藏
        isOpen.value = false
      }
    })
    return {
      isOpen,
      toggleOpen,
      dropdownRef
    }
  }
})
</script>

使用vue2实现,
采用自定义指令的方式:

全局定义指令:

    //    自定义指令clickoutside绑定了一个函数handleClose用来关闭菜单
        Vue.directives:{
            clickoutside:{
                bind:function(el,binding,vnode){
                    function documentHandler(e){
                        if(el.contains(e.target)){
                            return false;
                        }
                        if(binding.expression){
                            binding.value(e)
                        }
                    }
                    el._vueClickOutside_ = documentHandler;
                    document.addEventListener('click',documentHandler);
                },
                unbind:function(el,binding){
                    document.removeEventListener('click',el._vueClickOutside_);
                    delete el._vueClickOutside_;
                }
            }
        }

在组件中使用

<div class="mobile-menu" v-clickoutside="menuHandleClose">
    <img src="../assets/image/home/nav_logo.svg" >
    <div class="user-info flex"  >
        <img src="../assets/image/home/nav_down.png" @click="clickLogin">
        <a-icon type="menu" @click="menuListVisible = !menuListVisible" /> 
    </div>
</div>


<div v-if="menuListVisible">
 	<li>下拉列表1</li>
    <li>下拉列表2</li>
    <li>下拉列表3</li>
    <li>下拉列表4</li>
</div>



//....

 methods:{
 	 menuHandleClose(){
        this.menuListVisible=false
     }
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值