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函数中也就是组件或元素销毁的时候移除事件监听,不然,这些事件监听会一直存在在内存中。