vue自定义指令封装-是否点击当前元素以外区域
2026年5月23日 15:01
elementui中有对应指令封装,直接引入使用即可(下面有使用示例),如果不想依赖组件库,可以使用一下简单版本
1. 版本环境
- vue2
- 工程化脚手架
2. v-clickoutside 指令代码
// 点击外部的事件处理函数
function handleClickOutside(el, binding, e) {
// 判断点击的目标元素 是否 在绑定指令的元素 内部
if (el.contains(e.target)) return;
// 如果指令绑定的值为 false(比如弹出元素还未加载) 直接不执行
if (!binding.value || el.contains(e.target)) return;
// 触发绑定的回调函数(binding.value 就是指令绑定的方法)
if (typeof binding.value === "function") {
binding.value(e);
}
}
export default {
// 指令绑定到元素时触发,只执行一次
bind(el, binding) {
// 把事件处理函数挂载到元素实例上 方便后续解绑
// 避免多个指令实例共用一个函数导致冲突
el.__vueClickOutside__ = (e) => handleClickOutside(el, binding, e);
// 全局监听鼠标按下事件 mousedown 而非 click,响应更快无延迟
document.addEventListener("mousedown", el.__vueClickOutside__);
},
// 指令与元素解绑时触发 防止内存泄漏
unbind(el) {
// 移除全局事件监听
document.removeEventListener("mousedown", el.__vueClickOutside__);
// 删除元素上的自定义属性
delete el.__vueClickOutside__;
},
};
3. vu中 注册 指令
-
main.jsvue项目入口文件
import Vue from 'vue'
import App from './App.vue'
import clickoutside from '@/directives/clickoutside' // 替换为你的指令js文件所在目录
Vue.directive('clickoutside', clickoutside) // 注册指令
new Vue({
render: h => h(App),
}).$mount('#app')
4. 页面/组件中使用
<template>
<div>
<button @click="showPopup=true">打开弹出层</button>
<div class="popups" v-if="showPopup" v-clickoutside="showPopup && handleClose">
弹出层内容
</div>
</div>
</template>
<script>
export default {
data() {
return {
showPopup: false,
}
},
methods:{
handleClose() {
this.showPopup = false
},
}
}
</script>
element ui的指令使用示例
- vue3版本换成对应的语法 即可
<template>
<!-- 给需要监听外部点击的容器绑定指令 -->
<div class="custom-dropdown" v-clickoutside="closeMenu">
<el-button @click="isOpen = !isOpen">展开菜单</el-button>
<!-- 下拉内容 -->
<div v-show="isOpen" class="menu">
<p>菜单选项1</p>
<p>菜单选项2</p>
</div>
</div>
</template>
<script>
// import clickoutside from "element-ui/src/utils/clickoutside"; // 默认全局已注册,可单独引入
export default {
// directives: {
// clickoutside
// },
data() {
return {
isOpen: false // 控制菜单显示
}
},
methods: {
// 点击外部区域触发:关闭菜单
closeMenu() {
this.isOpen = false
}
}
}
</script>
<style scoped>
.custom-dropdown {
position: relative;
display: inline-block;
}
.menu {
position: absolute;
top: 40px;
left: 0;
width: 200px;
padding: 10px;
border: 1px solid #eee;
background: #fff;
}
</style>