vue3自定义指令--点击外部区域事件
vue
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
项目地址:https://gitcode.com/gh_mirrors/vu/vue
·
点击除输入框外的的区域,关闭弹框

clickOutside.ts
/***
* 点击外部事件
* @example
* import vClickOutside from '@/directives/clickOutside'
* v-click-outside="callback"
*/
import type {
ComponentPublicInstance,
DirectiveBinding,
ObjectDirective,
} from 'vue';
type DocumentHandler = <T extends MouseEvent>(mouseup: T, mousedown: T) => void;
type FlushList = Map<
HTMLElement,
{
documentHandler: DocumentHandler;
bindingFn: (...args: unknown[]) => unknown;
}
>;
type Nullable<T> = T | null;
const nodeList: FlushList = new Map();
let startClick: MouseEvent;
function on(
element: Element | HTMLElement | Document | Window,
event: string,
handler: EventListenerOrEventListenerObject,
): void {
if (element && event && handler) {
element.addEventListener(event, handler, false);
}
}
function createDocumentHandler(
el: HTMLElement,
binding: DirectiveBinding,
): DocumentHandler {
let excludes: HTMLElement[] = [];
if (Array.isArray(binding.arg)) {
excludes = binding.arg;
} else {
excludes.push(binding.arg as unknown as HTMLElement);
}
return function (mouseup, mousedown) {
const popperRef = (
binding.instance as ComponentPublicInstance<{
popperRef: Nullable<HTMLElement>;
}>
).popperRef;
const mouseUpTarget = mouseup.target as Node;
const mouseDownTarget = mousedown.target as Node;
const isBound = !binding || !binding.instance;
const isTargetExists = !mouseUpTarget || !mouseDownTarget;
const isContainedByEl =
el.contains(mouseUpTarget) || el.contains(mouseDownTarget);
const isSelf = el === mouseUpTarget;
const isTargetExcluded =
(excludes.length &&
excludes.some((item) => item?.contains(mouseUpTarget))) ||
(excludes.length && excludes.includes(mouseDownTarget as HTMLElement));
const isContainedByPopper =
popperRef &&
(popperRef.contains(mouseUpTarget) ||
popperRef.contains(mouseDownTarget));
if (
isBound ||
isTargetExists ||
isContainedByEl ||
isSelf ||
isTargetExcluded ||
isContainedByPopper
) {
return;
}
binding.value();
};
}
// 监听鼠标事件
on(document, 'mousedown', (e: Event) => (startClick = e as MouseEvent));
on(document, 'mouseup', (e: Event) => {
for (const { documentHandler } of nodeList.values()) {
documentHandler(e as MouseEvent, startClick);
}
});
const ClickOutside: ObjectDirective = {
beforeMount(el, binding) {
nodeList.set(el, {
documentHandler: createDocumentHandler(el, binding),
bindingFn: binding.value,
});
},
updated(el, binding) {
nodeList.set(el, {
documentHandler: createDocumentHandler(el, binding),
bindingFn: binding.value,
});
},
unmounted(el) {
nodeList.delete(el);
},
};
export default ClickOutside;
具体用法:可以直接在单个页面引入使用Index.vue ,也可以全局注册自定义指令main.ts
<!-- index.vue -->
<script setup lang="ts">
import vClickOutside from '@/directive/clickOutside'
import { ref } from 'vue'
const value = ref('')
const show = ref(false)
const focusHandle = () => {
show.value = true
}
const clickOutside = () => {
show.value = false
}
</script>
<template>
<div class="warp">
<el-input v-model="value" @focus="focusHandle" v-click-outside="clickOutside"></el-input>
<div class="box" v-show="show">
<ul>
<li v-for="item in 10" :key="item">{{ item }}</li>
</ul>
</div>
</div>
</template>
<style scoped lang="scss">
.warp {
display: flex;
flex-direction: column;
.box {
margin-top: 20px;
width: 300px;
height: 300px;
background-color: azure;
border-radius: 5px;
}
}
</style>
// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import ClickOutside from './directives/ClickOutside'
const app = createApp(App)
app.directive('click-outside', ClickOutside)
app.mount('#app')
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:4 个月前 )
9e887079
[skip ci] 1 年前
73486cb5
* chore: fix link broken
Signed-off-by: snoppy <michaleli@foxmail.com>
* Update packages/template-compiler/README.md [skip ci]
---------
Signed-off-by: snoppy <michaleli@foxmail.com>
Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 1 年前
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)