vue自定义指令封装-是否点击当前元素以外区域

elementui中有对应指令封装,直接引入使用即可(下面有使用示例),如果不想依赖组件库,可以使用一下简单版本

1. 版本环境

  • vue2
  • 工程化脚手架

2. v-clickoutside 指令代码

js 复制代码
// 点击外部的事件处理函数
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.js vue项目入口文件
js 复制代码
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. 页面/组件中使用

vue 复制代码
<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版本换成对应的语法 即可
vue 复制代码
<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>
相关推荐
xywww16822 分钟前
真实后台页实测:Opus 5 看图写前端的可用边界在哪
linux·服务器·前端·数据库·人工智能·gpt
小小尚@41 分钟前
AE脚本-AE Actions v1.1.8 操作动作记录器
开发语言·前端·javascript·jupyter·postman
大家的林语冰1 小时前
👍 超越 ESLint,Oxc 优先采用 TypeScript 7,Rust 和 Go 梦幻联动!
前端·javascript·typescript
樊小肆3 小时前
# 你还在等DeepSeek官方 agent Harness‌? 来试试 DeepSeeker-Code吧
前端·人工智能·后端
樊小肆3 小时前
2568 万 token 才花 2 块 2:聊聊 DeepSeeker-Code 怎么吃满上下文缓存
前端·人工智能·后端
JarvanMo3 小时前
Flutter 3.47: material/cupertino终于解耦了
前端
郭邯3 小时前
一次「字符洁癖」引发的思考:我用 AI 写了个全角半角转换工具
前端
想要成为糕糕手3 小时前
🚀 在浏览器里跑 DeepSeek-R1?WebGPU 端侧推理实战(五)—— 中断、重置、缓存与流式生成
前端·react.js·llm
GuWenyue3 小时前
后端接口又双叒没写好?3 步搭建前端 Mock,从此告别"傻等后端"
前端·mocha
海兰3 小时前
【数据采集】开源的 Web 数据采集与处理Firecrawl(一)
前端·开源