点击事件 事件委托的情况下实现阻止冒泡
生活随笔
收集整理的這篇文章主要介紹了
点击事件 事件委托的情况下实现阻止冒泡
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
最近在研究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來阻止冒泡
使用方式
?
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,遍歷后追加點擊事件
?
存在問題②
某個元素刪除后,點擊時候回調函數依舊會觸發
?
解決方案
建議:如果涉及到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包,點擊去查看
總結
以上是生活随笔為你收集整理的点击事件 事件委托的情况下实现阻止冒泡的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电阻学习看这篇就够了
- 下一篇: 颅脑外伤护理查房PPT模板