日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當(dāng)前位置:首頁(yè) > 科技  > 軟件

Vue 點(diǎn)擊彈窗外部,實(shí)現(xiàn)彈窗關(guān)閉?你有實(shí)現(xiàn)的思路嗎?

來(lái)源: 責(zé)編: 時(shí)間:2024-06-25 17:13:21 153觀看
導(dǎo)讀背景記得以前面試官問(wèn)過(guò)我一個(gè)問(wèn)題:我現(xiàn)在有一個(gè)彈窗,怎樣才能實(shí)現(xiàn)點(diǎn)擊彈窗以外的區(qū)域,實(shí)現(xiàn)關(guān)閉彈窗呢?當(dāng)時(shí)確實(shí)比較菜,沒(méi)想出應(yīng)該怎么做才行,因?yàn)楫?dāng)時(shí)我的腦子里只有 click事件,我在想點(diǎn)擊事件不是只能綁定在本元素身上嗎?怎

背景

記得以前面試官問(wèn)過(guò)我一個(gè)問(wèn)題:我現(xiàn)在有一個(gè)彈窗,怎樣才能實(shí)現(xiàn)點(diǎn)擊彈窗以外的區(qū)域,實(shí)現(xiàn)關(guān)閉彈窗呢?0zF28資訊網(wǎng)——每日最新資訊28at.com

當(dāng)時(shí)確實(shí)比較菜,沒(méi)想出應(yīng)該怎么做才行,因?yàn)楫?dāng)時(shí)我的腦子里只有 click事件,我在想點(diǎn)擊事件不是只能綁定在本元素身上嗎?怎么才能點(diǎn)擊其他地方來(lái)影響本元素呢?0zF28資訊網(wǎng)——每日最新資訊28at.com

0zF28資訊網(wǎng)——每日最新資訊28at.com

實(shí)現(xiàn)思路

過(guò)了一兩年后,回頭發(fā)現(xiàn),其實(shí)實(shí)現(xiàn)并不困難,很多人其實(shí)也都會(huì),換一種說(shuō)法,面試官想問(wèn)的是:在 Vue 中,有一個(gè)元素X,怎么做到點(diǎn)擊元素X以外的東西,觸發(fā)綁定在元素X上的事件。0zF28資訊網(wǎng)——每日最新資訊28at.com

我把實(shí)現(xiàn)思路分為幾步:0zF28資訊網(wǎng)——每日最新資訊28at.com

  • 定義一個(gè) Map,來(lái)收集彈窗元素
  • 監(jiān)聽(tīng) document 的鼠標(biāo)按下、松開(kāi)事件
  • document 鼠標(biāo)按下時(shí)記錄觸發(fā)的元素A
  • document 鼠標(biāo)松開(kāi)時(shí)遍歷 Map 中所有彈窗元素,讓這些彈窗元素跟元素A一一比較,不等于則說(shuō)明是點(diǎn)了彈窗元素外部,等于則說(shuō)明點(diǎn)擊了彈窗元素內(nèi)部
  • 點(diǎn)擊了外部則觸發(fā)綁定事件,點(diǎn)擊了內(nèi)部則不觸發(fā)

ClickOutside

其實(shí)上面的思路,就是 v-clickoutside的實(shí)現(xiàn)思路,這個(gè)自定義指令,是 Vue 中用的非常廣泛的指令~具體用法是這樣的:0zF28資訊網(wǎng)——每日最新資訊28at.com

cs () {  console.log('點(diǎn)擊外部')}<div v-clickoutside="cs"></div><button>點(diǎn)我</button><button>哈哈哈</button>

當(dāng)你點(diǎn)擊了 div 元素,也就是本元素,并不會(huì)觸發(fā)事件 cs,而當(dāng)你點(diǎn)擊它以外的元素,則會(huì)觸發(fā) cs 事件。0zF28資訊網(wǎng)——每日最新資訊28at.com

代碼實(shí)現(xiàn)

1.TypeScript類(lèi)型準(zhǔn)備

// vue自帶的一些類(lèi)型import type { ComponentPublicInstance, DirectiveBinding, ObjectDirective } from 'vue';// 下面會(huì)用到,是記錄綁定事件的函數(shù)type DocumentHandler = <T extends MouseEvent>(mouseup: T, mousedown: T) => void;// Map 的類(lèi)型// key 是元素本地// value 是綁定的事件type FlushList = Map<  HTMLElement,  DocumentHandler>;

2.綁定事件函數(shù)

首先封裝一個(gè)綁定事件的函數(shù),大家在平時(shí)封裝函數(shù)的時(shí)候一定要注意判空,兜底~0zF28資訊網(wǎng)——每日最新資訊28at.com

export function on(  element: Element | HTMLElement | Document | Window,  event: string,  handler: EventListenerOrEventListenerObject,): void {  if (element && event && handler) {    element.addEventListener(event, handler, false);  }}

3.判斷點(diǎn)擊元素是否是本元素

想一想我們的目的是啥,有一元素A,我需要點(diǎn)擊元素A以外的地方才觸發(fā)綁定的事件,點(diǎn)擊元素A或者元素A以?xún)?nèi)的區(qū)域則不觸發(fā)0zF28資訊網(wǎng)——每日最新資訊28at.com

所以這個(gè)函數(shù)主要做幾件事:0zF28資訊網(wǎng)——每日最新資訊28at.com

  • 判斷點(diǎn)擊的元素是否是本元素(不觸發(fā))
  • 判斷點(diǎn)擊的元素是否在本元素內(nèi)(不觸發(fā))
  • 兜底,判斷元素是否存在(觸發(fā))
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();  };}

4.自定義指令

自定義指令的幾個(gè)生命周期里,需要做這些事:0zF28資訊網(wǎng)——每日最新資訊28at.com

  • 綁定時(shí),記錄綁定元素與綁定事件到 nodeList 中
  • 更新時(shí),記錄綁定元素與綁定事件到 nodeList 中
  • 銷(xiāo)毀時(shí),將此元素從 nodeList 中抹除
// 記錄綁定元素的 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;

5.監(jiān)聽(tīng) document 鼠標(biāo)按下、松開(kāi)

萬(wàn)事俱備只欠東風(fēng),現(xiàn)在只需要監(jiān)聽(tīng) document 的鼠標(biāo)按下、松開(kāi)事件 即可,大概分為幾步:;0zF28資訊網(wǎng)——每日最新資訊28at.com

  • 鼠標(biāo)按下時(shí),記錄這個(gè)觸發(fā)的元素
  • 鼠標(biāo)松開(kāi)時(shí),遍歷 nodeList 中的元素,跟這個(gè)觸發(fā)元素做對(duì)比
  • 符合條件則執(zhí)行綁定事件,不符合則不執(zhí)行
let startClick: MouseEvent;on(document, 'mousedown', (e: MouseEvent) => (startClick = e));on(document, 'mouseup', (e: MouseEvent) => {  for (const { documentHandler } of nodeList.values()) {    documentHandler(e, startClick);  }});

這就實(shí)現(xiàn)了點(diǎn)擊外部觸發(fā)內(nèi)部事件的效果了!0zF28資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-96418-0.htmlVue 點(diǎn)擊彈窗外部,實(shí)現(xiàn)彈窗關(guān)閉?你有實(shí)現(xiàn)的思路嗎?

聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: 寧德時(shí)代曾毓群回應(yīng)“奮斗一百天”:號(hào)召練好基本功,沒(méi)有強(qiáng)迫大家

下一篇: Java 流式編程的七個(gè)必學(xué)技巧

標(biāo)簽:
  • 熱門(mén)焦點(diǎn)
Top 主站蜘蛛池模板: 满洲里市| 阳新县| 丹凤县| 海门市| 温州市| 共和县| 大同市| 手游| 乐安县| 朝阳县| 耿马| 浑源县| 宜城市| 论坛| 芜湖县| 密山市| 嘉荫县| 江津市| 安化县| 彰武县| 榕江县| 小金县| 普定县| 昭苏县| 莱州市| 西平县| 栾川县| 定陶县| 瓦房店市| 定远县| 韶关市| 南平市| 闽清县| 龙南县| 睢宁县| 曲沃县| 洛浦县| 营山县| 大同县| 宜丰县| 东方市|