日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

点击事件 事件委托的情况下实现阻止冒泡

發布時間:2024/3/24 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 点击事件 事件委托的情况下实现阻止冒泡 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

最近在研究react的事件,都說他是合成事件,整個dom唯一綁定事件的是document。
我想這不就是事件委托么,有啥好研究的,于是我去重溫了下事件委托,順便看了阻止冒泡。

突然突發奇想,如果兩個結合在一起呢?

能否實現子節點點擊了,父節點不能觸發點擊事件

好像n年前我還是小萌新,在廣電商做切圖仔的時候請教過我的組長,他沒有給到我滿意的答案。今天這個想法又冒出來了。
我得解決它一下。

先看看react是怎么解決的

它用了 e.nativeEvent.stopImmediatePropagation();
nativeEvent.stopImmediatePropagation是react自己新增的屬性方法。

那我的想法就來了。我也可以啊。

html

<div class="a"><div class="b"><div class="e">點擊<b>搗蛋鬼E</b>,會執行<B>e,b,a</B>函數</div><div class="c">點擊<b>搗蛋鬼C,stop</b>,執行執行<b>c</b>函數</div><div class="f">點擊<b>搗蛋鬼F</b>,會執行<b>f,b,a</b>函數</div></div></div>

javascript:
實現一個對象

  • 內部維護點擊事件的數組
  • 可以通過構造函數傳參的方式綁定委托事件的dom,如果不傳默認是body
  • 動態給事件回調函數的e對象添加_stop=true來阻止冒泡
function ProxyClickEvent(proxyBox) {var self = this;self.eventPool = [];if (proxyBox) {self._proxyBox = proxyBox;} else {self._proxyBox = document.body;}self.__bindEvent = self._bindEvent.bind(self);self._proxyBox.addEventListener("click", self.__bindEvent)}ProxyClickEvent.prototype._bindEvent = function(e) {let self = this;let target = e.target;for (let i = self.eventPool.length - 1; i >= 0; i--) {let event = self.eventPool[i];let fn = event.fn;/*** 1.如果target等于事件對應的dom* 2.否則事件dom是target的父節點&&e._target不為false* 3.如果e._stop為true時候,break* 那就執行回調函數* * **/if (event.dom == e.target) {fn(e);} else if (!e.__stop && event.dom.contains(e.target)) {fn(e);} else if (e.__stop) {break;}}}ProxyClickEvent.prototype.add = function(dom, fn) {if (!(dom instanceof HTMLElement)) {console.error("invalid parameter dom", dom, "fn", fn)throw "function add arg1 should be a HTMLElement,but get " + (typeof dom)}if (typeof fn !== "function") {console.error("invalid parameter dom", dom, "fn", fn)throw "function add arg2 should be a function,but get " + (typeof fn)}this.eventPool.push({dom: dom,fn: fn})}ProxyClickEvent.prototype.remove = function(dom, fn) {this.eventPool = this.eventPool.filter(item => item.dom != dom && item.fn != fn)}ProxyClickEvent.prototype.destroyed = function() {this.eventPool = [];self._proxyBox.removeEventListener("click", this.__bindEvent);}

使用方式
?

let proxyEvent = new ProxyClickEvent();window.onload = function() {proxyEvent.add(document.querySelector(".a"), function() {console.log("點擊了a")})proxyEvent.add(document.querySelector(".b"), function() {console.log("點擊了b")})proxyEvent.add(document.querySelector(".c"), function(e) {e.__stop = true;console.log("點擊了c")})proxyEvent.add(document.querySelector(".e"), function() {console.log("點擊了e")})proxyEvent.add(document.querySelector(".f"), function() {console.log("點擊了f")})}


這存在在個問題①

必須得從父級到子節點,按順序add,否則事件“冒泡順序”會錯亂


目前先假設使用場景場景:
用戶可以自己明確且可以控制從父級到自己按順序的add

例如以下場景就非常適用:

通過dom自定義屬性clickFn來綁定函數名字,然后獲取攜帶clickFn屬性的dom,遍歷后追加點擊事件
?

<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><div class="a" clickFn="fna"><div class="b" clickFn="fnb"><div class="e" clickFn="fne">點擊<b>搗蛋鬼E</b>,會執行<B>e,b,a</B>函數</div><div class="c" clickFn="fnc">點擊<b>搗蛋鬼C,stop</b>,執行執行<b>c</b>函數</div><div class="f" clickFn="fnf">點擊<b>搗蛋鬼F</b>,會執行<b>f,b,a</b>函數</div></div></div><script src="./ProxyClickEvent.js"></script><script>var funs = {fna: function() {console.log("點擊a")},fnb: function() {console.log("點擊b")},fnc: function(e) {e.__stop = true;console.log("點擊c")},fnd: function() {console.log("點擊d")},fne: function() {console.log("點擊e")},fnf: function() {console.log("點擊f")}}window.onload = function() {let proxyEvent = new ProxyClickEvent();let clickDoms = document.querySelectorAll("[clickFn]");for (let i = 0; i < clickDoms.length; i++) {let dom = clickDoms[i];let fnStr = clickDoms[i].getAttribute("clickFn");proxyEvent.add(dom, funs[fnStr])}}</script> </body></html>

存在問題②


某個元素刪除后,點擊時候回調函數依舊會觸發
?

解決方案

  • 暴力定時檢測更新dom是否存在,過濾掉數組里面dom不存在的元素,
  • 并且提供函數destroy時候銷毀定時器
  • 因為定時任務只是更新數組變量不涉及費時操作,所以不需要當心性能問題
  • 如果是單頁面的話,必須在頁面銷毀前調用destroy函數,銷毀定時器
  • 建議:如果涉及到dom的父子節點的增刪的話,必須清空數組,然后再遍歷添加到數組

    代碼:

    function ProxyClickEvent(proxyBox) {var self = this;self.eventPool = [];if (proxyBox) {self._proxyBox = proxyBox;} else {self._proxyBox = document.body;}//更新數組,過濾掉被銷毀的dom的事件self._bind_clearRemoveDomEventItem = self._clearRemoveDomEventItem.bind(self);//定時過濾dom不存在的元素self._timer = setInterval(function() {self._bind_clearRemoveDomEventItem();}, 1000)self.__bindEvent = self._bindEvent.bind(self);self._proxyBox.addEventListener("click", self.__bindEvent) } ProxyClickEvent.prototype._clearRemoveDomEventItem = function() {if (this.eventPool.some((el) => !document.body.contains(el.dom))) {this.eventPool = this.eventPool.filter(item => document.body.contains(item.dom));} } ProxyClickEvent.prototype._bindEvent = function(e) {let self = this;let target = e.target;for (let i = self.eventPool.length - 1; i >= 0; i--) {let event = self.eventPool[i];let fn = event.fn;/*** 1.如果target等于事件對應的dom* 2.否則事件dom是target的父節點&&e._target不為false* 3.如果e._stop為true時候,break* 那就執行回調函數* * **/if (event.dom == target) {fn(e);} else if (!e.__stop && event.dom.contains(target)) {fn(e);} else if (e.__stop) {break;}} } ProxyClickEvent.prototype.add = function(dom, fn) {if (!(dom instanceof HTMLElement)) {console.error("invalid parameter dom", dom, "fn", fn)throw "function add arg1 should be a HTMLElement,but get " + (typeof dom)}if (typeof fn !== "function") {console.error("invalid parameter dom", dom, "fn", fn)throw "function add arg2 should be a function,but get " + (typeof fn)}this.eventPool.push({dom: dom,fn: fn}) } ProxyClickEvent.prototype.remove = function(dom, fn) {this.eventPool = this.eventPool.filter(item => item.dom != dom && item.fn != fn) } ProxyClickEvent.prototype.destroy = function() {this.eventPool = [];this._proxyBox.removeEventListener("click", this.__bindEvent);clearInterval(this._timer); }


    已封裝成npm包,點擊去查看

    總結

    以上是生活随笔為你收集整理的点击事件 事件委托的情况下实现阻止冒泡的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。