記得以前面試官問過我一個問題:我現在有一個彈窗,怎樣才能實現點擊彈窗以外的區域,實現關閉彈窗呢?
當時確實比較菜,沒想出應該怎么做才行,因為當時我的腦子里只有 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); }});
這就實現了點擊外部觸發內部事件的效果了!
本文鏈接:http://www.tebozhan.com/showinfo-26-96418-0.htmlVue 點擊彈窗外部,實現彈窗關閉?你有實現的思路嗎?
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
上一篇: 寧德時代曾毓群回應“奮斗一百天”:號召練好基本功,沒有強迫大家
下一篇: Java 流式編程的七個必學技巧