欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 创投人物 > Vue中自定义指令:ClickOutside(点击当前模块外的位置)

Vue中自定义指令:ClickOutside(点击当前模块外的位置)

2025/3/12 4:13:59 来源:https://blog.csdn.net/qq_38210427/article/details/146144643  浏览:    关键词:Vue中自定义指令:ClickOutside(点击当前模块外的位置)

应用场景

假设我们有一个下拉框组件,当下拉框展开的时候,点击下拉框之外的元素可以自动关闭下拉框。

一 ClickOutside代码示例

在vue3中使用ClickOutside

// 导入自定义指令
import { ClickOutside as vClickOutside } from 'element-plus';// 绑定指令触发对应事件
<div id="d1" v-click-outside="closeOrder">暂无数据
</div>// 写相关逻辑事件
const closeOrder = () => {console.log('点击了d1区域之外的位置')
}

id="d1"记得写,否则不生效



vue2中使用ClickOutside

// 导入指令
import { ClickOutside } from 'element-plus';// 映射该指令
directives:{ ClickOutside }// 绑定指令触发对应事件
<div id="d1" v-clickOutside="closeOrder">暂无数据
</div>// 写相关逻辑事件
closeOrder(){console.log('点击了d1区域之外的位置')
}

案例

<template><div ref="dropdownRef" class="drop_down" id="d1" v-click-outside="closeOrder"><div class="cascade-input" @click="toggleDropdown" :class="{ 'is-active': isDropdownVisible }"><span class="cascade_choose">请选择</span><el-icon :class="{ 'is-rotate': isDropdownVisible }" class="down"><ArrowDown /></el-icon></div><div class="cascade-dropdown" v-if="isDropdownVisible"><div style="display: flex"><!-- 一级菜单 --><ul><liclass="cascade_item"v-for="(item, index) in cascadeType":key="index"@click="chooseType(item.field)":class="{ active: chooseTypeIndex == item.field }"><span class="cascade_item_name">{{ item.name }}</span><span class="cascade_item_name"><el-icon><ArrowRight /></el-icon></span></li></ul><!-- 二级菜单 --><div class="choose" v-show="isShowTwoMenu"><div class="choose_header"><ul><listyle="cursor: pointer"v-for="(item, index) in MustList"@click="changeMustTab(item.id)":key="index":class="{ 'is-must': isMust == item.id }">{{ item.name }}</li></ul></div><div class="choose_content"><ul><template v-for="item in secondList" :key="item.id"><liv-if="!item.subImportField"style="cursor: pointer"@click="changeItem(item.id)":class="{ 'is-choose': isChooseItem == item.id }">{{ item.name }}</li><template v-if="item.subImportField?.length > 0"><div class="links">以下联系方式至少选一种</div><liv-for="i in item.subImportField":key="i.id"style="cursor: pointer"@click="changeItem(i.id)":class="{ 'is-choose': isChooseItem == i.id }">{{ i.name }}</li></template></template></ul></div><div class="choose_footer"> 新增自定义字段 </div></div></div></div></div>
</template>
<script setup lang="ts">
import { ArrowDown, ArrowRight } from "@element-plus/icons-vue"
import { ClickOutside as vClickOutside } from "element-plus"
/*** 切换*/
const isDropdownVisible = ref(false)const cascadeType = ref([{field: 1,name: "客户"},{field: 2,name: "联系人"},{field: 3,name: "跟进记录"}
])
const toggleDropdown = () => {// debuggerisDropdownVisible.value = !isDropdownVisible.valueconsole.log("isDropdownVisible.value", isDropdownVisible.value)if (!isDropdownVisible.value) {isShowTwoMenu.value = falsechooseTypeIndex.value = null}
}const closeOrder = () => {console.log("点击了d1区域之外的位置")isDropdownVisible.value = false
}// const dropdownRef = ref(null)
// const handleClickOutside = (event) => {
//   if (dropdownRef.value && !dropdownRef.value.contains(event.target)) {
//     isDropdownVisible.value = false
//   }
// }// onMounted(() => {
//   debugger
//   document.addEventListener("click", handleClickOutside)
// })// onBeforeUnmount(() => {
//   document.removeEventListener("click", handleClickOutside)
// })//切换类型
const chooseTypeIndex = ref<any>(null)
//展示二级菜单
const isShowTwoMenu = ref(false)const secondList = ref<any>([])
// const secondListByNoMust = ref<any>([])
const chooseType = (field: any) => {chooseTypeIndex.value = fieldisShowTwoMenu.value = trueisMust.value = 1// 获取二级菜单数据switch (field) {case 1:secondList.value = [{name: "称谓",id: 111,type: 0},{name: "生日",id: 22,type: 0},{name: "联系方式",id: 23,type: 1,subImportField: [{name: "邮箱",id: 24},{name: "手机",id: 25}]}]breakcase 2:secondList.value = [{name: "传真",id: 111,type: 0},{name: "职务",id: 22,type: 0}]break}
}const isChooseItem = ref("")
const changeItem = (id: any) => {isChooseItem.value = id
}// 切换必须非必选
const isMust = ref(1)
const MustList = ref([{name: "必须",id: 1},{name: "非必须",id: 2}
])
const changeMustTab = (id) => {isMust.value = idisChooseItem.value = ""switch (id) {case 1:secondList.value = [{name: "称谓",id: 111,type: 0},{name: "生日",id: 22,type: 0},{name: "联系方式",id: 23,type: 1,subImportField: [{name: "邮箱",id: 24},{name: "手机",id: 25}]}]breakcase 2:secondList.value = [{name: "传真",id: 111,type: 0},{name: "职务",id: 22,type: 0}]break}
}
</script>
<style scoped lang="scss">
.drop_down {position: relative;.cascade-input {height: 40px;padding: 0px 12px;border: 1px solid #ccc;border-radius: 4px;cursor: pointer;user-select: none;display: flex;justify-content: space-between;align-items: center;position: relative;.cascade_choose {color: #333333;font-size: 16px;font-weight: 400;}}.cascade-input.is-active {border-color: #409eff;}.down {transition: all 0.4s;}.is-rotate {transform: rotate(180deg);}.cascade-dropdown {position: absolute;top: 40px;left: 0px;z-index: 9999;display: inline-block;box-shadow: 0 2px 9px 0 #c8c9cc80;height: 291px;background: #fff;border-radius: 2px;border: 1px solid #ebedf0;border-radius: 4px;margin-top: 4px;.active {background: #f7f8fa;}.cascade_item {width: 240px;height: 36px;display: flex;justify-content: space-between;align-items: center;padding: 0px 12px;cursor: pointer;.cascade_item_name {color: #323233;font-size: 14px;font-weight: 400;}}.choose {width: 240px;height: 291px;border-left: 1px solid #dcdfe6;position: relative;.choose_header {width: 100%;ul {display: flex;height: 36px;line-height: 36px;border-bottom: 1px solid #dedede;box-sizing: border-box;padding-left: 10px;li {margin-right: 20px;color: #323233;font-size: 14px;font-weight: 500;&:hover {cursor: pointer;}}}.is-must {color: #477fff;border-bottom: 1px solid #477fff;}}.choose_content {// padding-left: 12px;ul {li {height: 32px;line-height: 32px;padding-left: 12px;}.is-choose {background: #f7f8fa;}}.links {color: #477fff;font-size: 12px;font-family: "苹方";padding: 5px 0px 5px 12px;}}.choose_footer {position: absolute;left: 0;bottom: 0;width: 92%;height: 40px;line-height: 40px;text-align: center;border-top: 1px solid #dcdfe6;color: #477fff;font-size: 14px;font-weight: 400;margin: 0px 10px;}}}
}
</style>

热搜词