vue 自定义指令 实现点击下拉菜单外部区域关闭下拉菜单

我们来看下常见的下拉菜单:
在这里插入图片描述

这里我们点击菜单,下拉菜单就会显示,点击下拉菜单以外的区域就会隐藏。

这是一个简单的例子:
在这里插入图片描述

这里增加一个选项,就是当我们按下esc键的时候,下拉菜单也可以关闭。
先贴出代码:

<template>
  <div v-cloak v-clickoutside="outsideClose" class="dropmain">
    <div @click="show = !show" class="dropbutton">
      测试下拉菜单
    </div>
    <div class="dropdown" v-show="show">
      <P>点击下拉菜单显示菜单内容,点击外部区域可关闭下拉菜单</P>
    </div>
  </div>
</template>

<script>
  export default {
    name: "DropDown",
    data() {
      return {
        show: false,
      }
    },
    directives: {
      clickoutside: {
        bind(el, binding, vnode) {
          function documentHandler(e) {
            if (el.contains(e.target)) {
              return false
            }
            if (binding.expression) {
              binding.value(e)
            }
          }

          function KeyUp(e) {
            if (e.keyCode == 27) {
              if (binding.expression) {
                binding.value(e)
              }
            }
          }
          el.__vueClickOutSize__ = documentHandler
          el.__vueKeyup__ = KeyUp
          
          document.addEventListener('keyup', KeyUp)
          document.addEventListener('click', documentHandler)
        },
        unbind(el, binding) {
          document.removeEventListener('click', el.__vueClickOutSize__)
          delete  el.__vueClickOutSize__

          document.removeEventListener('keyup', el.__vueKeyup__)
          delete  el.__vueKeyup__
        }
      }
    },
    methods: {
      outsideClose() {
        this.show = false
      }
    }
  }
</script>

<style scoped>
  [v-cloak] {
    display: none;
  }

  .dropmain {
    width: 150px;
  }

  .dropbutton {
    display: block;
    width: 100%;
    padding: 5px;
    color: #fff;
    background-color: #39f;
    text-align: center;
    font-size: 12px;
    border-radius: 4px;
    cursor: pointer;
    outline: none;
    user-select: none;
  }

  .dropdown {
    width: 100%;
    padding: 5px;
    font-size: 12px;
    background-color: #fff;
    border-radius: 4px;
    box-shadow: 0 1px 6px rgba(0, 0, 0, .2);
    text-align: left;
    margin-top: 2px;
  }

</style>

我们先来看下el,binding,vnode分别是什么:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

其中这里的主要逻辑是:如果点击区域是在元素内部,那么返回。如果绑定了expression,在这里我们需要的是一个函数,那么就执行用户自定义的函数方法。

注意这里的expression可能值有很多,如果你不注意写了其他的那么程序可能不会达到你的预期。

 binding.value(e)

这个大家在看上面的具体内容时都知道了 binding.value是一个函数,用来执行用户绑定的expression,也就是函数。
在这里插入图片描述

el.__vueClickOutSize__
 el.__vueKeyup_

这两个是我们自己声明的变量,因为在vue2.x中不能使用this.xxxx的形式在上下文中声明一个变量,它们的作用是在unbind函数中也就是组件或元素销毁的时候移除事件监听,不然,这些事件监听会一直存在在内存中。

  • 6
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值