记得以前面试官问过我一个问题:我现在有一个弹窗,怎样才能实现点击弹窗以外的区域,实现关闭弹窗呢?
当时确实比较菜,没想出应该怎么做才行,因为当时我的脑子里只有 click事件,我在想点击事件不是只能绑定在本元素身上吗?怎么才能点击其他地方来影响本元素呢?
过了一两年后,回头发现,其实实现并不困难,很多人其实也都会,换一种说法,面试官想问的是:在 Vue 中,有一个元素X,怎么做到点击元素X以外的东西,触发绑定在元素X上的事件。
我把实现思路分为几步:
其实上面的思路,就是 v-clickoutside的实现思路,这个自定义指令,是 Vue 中用的非常广泛的指令~具体用法是这样的:
cs () { console.log('点击外部')}<div v-clickoutside="cs"></div><button>点我</button><button>哈哈哈</button>
当你点击了 div 元素,也就是本元素,并不会触发事件 cs,而当你点击它以外的元素,则会触发 cs 事件。
// vue自带的一些类型import type { ComponentPublicInstance, DirectiveBinding, ObjectDirective } from 'vue';// 下面会用到,是记录绑定事件的函数type DocumentHandler = <T extends MouseEvent>(mouseup: T, mousedown: T) => void;// Map 的类型// key 是元素本地// value 是绑定的事件type FlushList = Map< HTMLElement, DocumentHandler>;
首先封装一个绑定事件的函数,大家在平时封装函数的时候一定要注意判空,兜底~
export function on( element: Element | HTMLElement | Document | Window, event: string, handler: EventListenerOrEventListenerObject,): void { if (element && event && handler) { element.addEventListener(event, handler, false); }}
想一想我们的目的是啥,有一元素A,我需要点击元素A以外的地方才触发绑定的事件,点击元素A或者元素A以内的区域则不触发
所以这个函数主要做几件事:
function createDocumentHandler(el: HTMLElement, binding: DirectiveBinding): DocumentHandler { return function (mouseup, mousedown) { 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; if ( isBound || isTargetExists || isContainedByEl || isSelf ) { return; } binding.value(); };}
自定义指令的几个生命周期里,需要做这些事:
// 记录绑定元素的 Mapconst nodeList: FlushList = new Map();const ClickOutside: ObjectDirective = { beforeMount(el, binding) { nodeList.set(el, createDocumentHandler(el, binding)); }, updated(el, binding) { nodeList.set(el, createDocumentHandler(el, binding)); }, unmounted(el) { nodeList.delete(el); },};export default ClickOutside;
万事俱备只欠东风,现在只需要监听 document 的鼠标按下、松开事件 即可,大概分为几步:;
let startClick: MouseEvent;on(document, 'mousedown', (e: MouseEvent) => (startClick = e));on(document, 'mouseup', (e: MouseEvent) => { for (const { documentHandler } of nodeList.values()) { documentHandler(e, startClick); }});
这就实现了点击外部触发内部事件的效果了!
本文链接://www.dmpip.com//www.dmpip.com/showinfo-26-96418-0.htmlVue 点击弹窗外部,实现弹窗关闭?你有实现的思路吗?
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com
上一篇: 宁德时代曾毓群回应“奋斗一百天”:号召练好基本功,没有强迫大家
下一篇: Java 流式编程的七个必学技巧