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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

addeventlistener事件第三个参数_简析JavaScript 事件绑定、事件冒泡、事件捕获和事件执行顺序...

發布時間:2025/3/19 javascript 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 addeventlistener事件第三个参数_简析JavaScript 事件绑定、事件冒泡、事件捕获和事件执行顺序... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

這篇文章主要介紹了javaScript 事件綁定、事件冒泡、事件捕獲和事件執行順序整理總結的相關資料

(一)事件綁定的幾種方式

javascript給DOM綁定事件處理函數總的來說有2種方式:在html文檔中綁定、在js代碼中綁定。

下面的方式1、方式2屬于在html中綁定事件,方式3、方式4和方式5屬于在js代碼中綁定事件,其中方法5是最推薦的做法。

方式1:

HTML的DOM元素支持onclick、onblur等以on開頭屬性,我們可以直接在這些屬性值中編寫javascript代碼。當點擊div的時候,下面的代碼會彈出div的ID:

????<div?id="outestA"?οnclick="var?id?=?this.id;alert(id);return?false;">div>

這種做法很顯然不好,因為代碼都是放在字符串里的,不能格式化和排版,當代碼很多的時候很難看懂。這里有一點值得說明:onclick屬性中的this代表的是當前被點擊的DOM對象,所以我們可以通過this.id獲取DOM元素的id屬性值。

方式2:

當代碼比較多的時候,我們可以在onclick等屬性中指定函數名。

????<script>function?buttonHandler(thisDom){
?????????alert(this.id);//undefined
?????????alert(thisDom.id);//outestAreturn?false;
?????????}script>

????<div?id="outestA"?onclick="return?buttonHandler(this);">div>

跟上面的做法相比,這種做法略好一些。值得一提的是:事件處理函數中的this代表的是window對象,所以我們在onclick屬性值中,通過this將dom對象作為參數傳遞。

方式3:在JS代碼中通過dom元素的onclick等屬性

??var?dom?=?document.getElementById("outestA");

????dom.onclick?=?function(){alert("1="?+?this.id);};

????dom.onclick?=?function(){alert("2="?+?this.id);};

這種做法this代表當前的DOM對象。還有一點:這種做法只能綁定一個事件處理函數,后面的會覆蓋前面的。

方式4:IE下使用attachEvent/detachEvent函數進行事件綁定和取消。

attachEvent/detachEvent兼容性不好,IE6~IE11都支持該函數,但是FF和Chrome瀏覽器都不支持該方法。而且attachEvent/detachEvent不是W3C標準的做法,所以不推薦使用。在IE瀏覽器下,attachEvent有以下特點。

a) 事件處理函數中this代表的是window對象,不是dom對象。

????????var?dom?=?document.getElementById("outestA");?

?????????dom.attachEvent('onclick',a);?

???????????function?a()?{??

????????????alert(this.id);//undefined?

???????????}

b) 同一個事件處理函數只能綁定一次。

????????var?dom?=?document.getElementById("outestA");?

????????dom.attachEvent('onclick',a);?

????????dom.attachEvent('onclick',a);??

????????function?a()?{?

?????????alert(this.id);

????????}

雖然使用attachEvent綁定了2次,但是函數a只會調用一次。

c)不同的函數對象,可以重復綁定,不會覆蓋。

var?dom?=?document.getElementById("outestA");?

????????dom.attachEvent('onclick',function(){alert(1);});?

????????dom.attachEvent('onclick',function(){alert(1);});?//?當outestA的click事件發生時,會彈出2個對話框?

匿名函數和匿名函數是互相不相同的,即使代碼完全一樣。所以如果我們想用detachEvent取消attachEvent綁定的事件處理函數,那么綁定事件的時候不能使用匿名函數,必須要將事件處事函數單獨寫成一個函數,否則無法取消。

方式5:使用W3C標準的addEventListener和removeEventListener。

這2個函數是W3C標準規定的,FF和Chrome瀏覽器都支持,IE6/IE7/IE8都不支持這2個函數。不過從IE9開始就支持了這2個標準的API。

????????????//?type:事件類型,不含"on",比如"click"、"mouseover"、"keydown";

????????????//?而attachEvent的事件名稱,含含"on",比如"onclick"、"onmouseover"、"onkeydown";

????????????//?listener:事件處理函數

????????????//?useCapture是事件冒泡,還是事件捕獲,默認false,代表事件冒泡類型

????????????addEventListener(type,?listener,?useCapture);?

a) 事件處理函數中this代表的是dom對象,不是window,這個特性與attachEvent不同。

?var?dom?=?document.getElementById("outestA");?

???????????dom.addEventListener('click',?a,?false);?



??????????function?a()?{??

??????????alert(this.id);//outestA?

????????}

b) 同一個事件處理函數可以綁定2次,一次用于事件捕獲,一次用于事件冒泡。

var?dom?=?document.getElementById("outestA");?

??????????dom.addEventListener('click',?a,?false);?

????????dom.addEventListener('click',?a,?true);?



????????function?a()?{??

??????????????alert(this.id);//outestA?

????????}//?當點擊outestA的時候,函數a會調用2次

如果綁定的是同一個事件處理函數,并且都是事件冒泡類型或者事件捕獲類型,那么只能綁定一次。

var?dom?=?document.getElementById("outestA");?

????????dom.addEventListener('click',?a,?false);?

????????dom.addEventListener('click',?a,?false);?



????????function?a()?{??

??????????????alert(this.id);//outestA?

????????}



????//?當點擊outestA的時候,函數a只會調用1次

c) 不同的事件處理函數可以重復綁定,這個特性與attachEvent一致。

(二)事件處理函數的執行順序

方式1、方式2和方式3都不能實現事件的重復綁定,所以自然也就不存在執行順序的問題。方式4和方式5可以重復綁定特性,所以需要了解下執行順序的問題。

如果你寫出依賴于執行順序的代碼,可以斷定你的設計存在問題。所以下面的順序問題,僅作為興趣探討,沒有什么實際意義。

直接上結論:addEventListener和attachEvent表現一致,如果給同一個事件綁定多個處理函數,先綁定的先執行。

下面的代碼我在IE11、FF17和Chrome39都測試過。

<script>window.onload?=?function(){var?outA?=?document.getElementById("outA");?
????????????outA.addEventListener('click',function(){alert(1);},false);
?????????????outA.addEventListener('click',function(){alert(2);},true);
?????????????outA.addEventListener('click',function(){alert(3);},true);
?????????????outA.addEventListener('click',function(){alert(4);},true);
?????????};script>
????<body>

?????????<div?id="outA"?style="width:400px;?height:400px;?background:#CDC9C9;position:relative;">

????????div>

????body>

當點擊outA的時候,會依次打印出1、2、3、4。這里特別需要注意:我們給outA綁定了多個onclick事件處理函數,也是直接點擊outA觸發的事件,所以不涉及事件冒泡和事件捕獲的問題,即addEventListener的第三個參數在這種場景下,沒有什么用處。

如果是通過事件冒泡或者是事件捕獲觸發outA的click事件,那么函數的執行順序會有變化。

(三) 事件冒泡和事件捕獲

事件冒泡和事件捕獲很好理解,只不過是對同一件事情的不同看法,只不過這2種看法都很有道理。

我們知道HTML中的元素是可以嵌套的,形成類似于樹的層次關系。比如下面的代碼:

?<div?id="outA"?style="width:400px;?height:400px;?background:#CDC9C9;position:relative;">

????????<div?id="outB"?style="height:200;?background:#0000ff;top:100px;position:relative;">

????????????<div?id="outC"?style="height:100px;?background:#FFB90F;top:50px;position:relative;">div>

???????????div>

????div>

如果點擊了最內側的outC,那么外側的outB和outC算不算被點擊了呢?很顯然算,不然就沒有必要區分事件冒泡和事件捕獲了,這一點各個瀏覽器廠家也沒有什么疑義。

假如outA、outB、outC都注冊了click類型事件處理函數,當點擊outC的時候,觸發順序是A-->B-->C,還是C-->B-->A呢?如果瀏覽器采用的是事件冒泡,那么觸發順序是C-->B-->A,由內而外,像氣泡一樣,從水底浮向水面;如果采用的是事件捕獲,那么觸發順序是A-->B-->C,從上到下,像石頭一樣,從水面落入水底。

事件冒泡見下圖:

事件捕獲見下圖:

一般來說事件冒泡機制,用的更多一些,所以在IE8以及之前,IE只支持事件冒泡。

IE9+/FF/Chrome這2種模型都支持,可以通過addEventListener((type, listener, useCapture)的useCapture來設定,useCapture=false代表著事件冒泡,useCapture=true代表著采用事件捕獲。

????<script>window.onload?=?function(){var?outA?=?document.getElementById("outA");?var?outB?=?document.getElementById("outB");?var?outC?=?document.getElementById("outC");?//?使用事件冒泡
?????outA.addEventListener('click',function(){alert(1);},false);
?????outB.addEventListener('click',function(){alert(2);},false);
?????outC.addEventListener('click',function(){alert(3);},false);
?????};script>
????<body>

????????<div?id=“outA”?style=“width:400px;?height:400px;?background:#CDC9C9;position:relative;”>

????????????<div?id=“outB”?style=“height:200;?background:#0000ff;top:100px;position:relative;”>

????????????????<div?id=“outC”?style=“height:100px;?background:#FFB90F;top:50px;position:relative;”>div>

????????????div>

????????div>

????body>

使用的是事件冒泡,當點擊outC的時候,打印順序是3-->2-->1。如果將false改成true使用事件捕獲,打印順序是1-->2-->3。

(四) DOM事件流

DOM事件流我也不知道怎么解釋,個人感覺就是事件冒泡和事件捕獲的結合體,直接看圖吧。

DOM事件流:將事件分為三個階段:捕獲階段、目標階段、冒泡階段。先調用捕獲階段的處理函數,其次調用目標階段的處理函數,最后調用冒泡階段的處理函數。

這個過程很類似于Struts2框中的action和Interceptor。當發出一個URL請求的時候,先調用前置攔截器,其次調用action,最后調用后置攔截器。

<script>window.onload?=?function(){var?outA?=?document.getElementById("outA");?var?outB?=?document.getElementById("outB");?var?outC?=?document.getElementById("outC");?//?目標(自身觸發事件,是冒泡還是捕獲無所謂)
?????outC.addEventListener('click',function(){alert("target");},true);//?事件冒泡
?????outA.addEventListener('click',function(){alert("bubble1");},false);
?????outB.addEventListener('click',function(){alert("bubble2");},false);//?事件捕獲
?????outA.addEventListener('click',function(){alert("capture1");},true);
?????outB.addEventListener('click',function(){alert("capture2");},true);?
?};script>



<body>

????<div?id=“outA”?style=“width:400px;?height:400px;?background:#CDC9C9;position:relative;”>

????????<div?id=“outB”?style=“height:200;?background:#0000ff;top:100px;position:relative;”>

????????????<div?id=“outC”?style=“height:100px;?background:#FFB90F;top:50px;position:relative;”>div>

????????div>

????div>

body>

當點擊outC的時候,依次打印出capture1-->capture2-->target-->bubble2-->bubble1。到這里是不是可以理解addEventListener(type,handler,useCapture)這個API中第三個參數useCapture的含義呢?

useCapture=false意味著:將事件處理函數加入到冒泡階段,在冒泡階段會被調用;

useCapture=true意味著:將事件處理函數加入到捕獲階段,在捕獲階段會被調用。

從DOM事件流模型可以看出,捕獲階段的事件處理函數,一定比冒泡階段的事件處理函數先執行。

(五) 再談事件函數執行先后順序

在DOM事件流中提到過:

// 目標(自身觸發事件,是冒泡還是捕獲無所謂)

outC.addEventListener('click',function(){alert("target");},true);

我們在outC上觸發onclick事件(這個是目標對象),如果我們在outC上同時綁定捕獲階段/冒泡階段事件處理函數會怎么樣呢?

????<script>window.onload?=?function(){var?outA?=?document.getElementById("outA");?var?outB?=?document.getElementById("outB");?var?outC?=?document.getElementById("outC");?//?目標(自身觸發事件,是冒泡還是捕獲無所謂)
?????outC.addEventListener('click',function(){alert("target2");},true);
?????outC.addEventListener('click',function(){alert("target1");},true);//?事件冒泡
?????outA.addEventListener('click',function(){alert("bubble1");},false);
?????outB.addEventListener('click',function(){alert("bubble2");},false);//?事件捕獲
?????outA.addEventListener('click',function(){alert("capture1");},true);
?????outB.addEventListener('click',function(){alert("capture2");},true);
?????};script>



????<body>

????????<div?id=“outA”?style=“width:400px;?height:400px;?background:#CDC9C9;position:relative;”>

????????????<div?id=“outB”?style=“height:200;?background:#0000ff;top:100px;position:relative;”>

????????????????????<div?id=“outC”?style=“height:100px;?background:#FFB90F;top:50px;position:relative;”>div>

???????????????div>

???????????div>

????body>

點擊outC的時候,打印順序是:capture1-->capture2-->target2-->target1-->bubble2-->bubble1。

由于outC是我們觸發事件的目標對象,在outC上注冊的事件處理函數,屬于DOM事件流中的目標階段。

目標階段函數的執行順序:先注冊的先執行,后注冊的后執行。這就是上面我們說的,在目標對象上綁定的函數是采用捕獲,還是采用冒泡,都沒有什么關系,因為冒泡和捕獲只是對父元素上的函數執行順序有影響,對自己沒有什么影響。如果不信,可以將下面的代碼放進去驗證。

//?目標(自身觸發事件,是冒泡還是捕獲無所謂)

????outC.addEventListener('click',function(){alert("target1");},false);

????outC.addEventListener('click',function(){alert("target2");},true);

????outC.addEventListener('click',function(){alert("target3");},true);

????outC.addEventListener('click',function(){alert("target4");},false);

至此我們可以給出事件函數執行順序的結論了:捕獲階段的處理函數最先執行,其次是目標階段的處理函數,最后是冒泡階段的處理函數。目標階段的處理函數,先注冊的先執行,后注冊的后執行。

(六) 阻止事件冒泡和捕獲

默認情況下,多個事件處理函數會按照DOM事件流模型中的順序執行。如果子元素上發生某個事件,不需要執行父元素上注冊的事件處理函數,那么我們可以停止捕獲和冒泡,避免沒有意義的函數調用。前面提到的5種事件綁定方式,都可以實現阻止事件的傳播。

由于第5種方式,是最推薦的做法。所以我們基于第5種方式,看看如何阻止事件的傳播行為。IE8以及以前可以通過 window.event.cancelBubble=true阻止事件的繼續傳播;IE9+/FF/Chrome通過event.stopPropagation()阻止事件的繼續傳播。

<script>window.onload?=?function(){var?outA?=?document.getElementById("outA");?var?outB?=?document.getElementById("outB");?var?outC?=?document.getElementById("outC");?//?目標
?outC.addEventListener('click',function(event){
??alert("target");
??event.stopPropagation();
?},false);//?事件冒泡
?outA.addEventListener('click',function(){alert("bubble");},false);//?事件捕獲
?outA.addEventListener('click',function(){alert("capture");},true);?
?};script>



<body>

????<div?id=“outA”?style=“width:400px;?height:400px;?background:#CDC9C9;position:relative;”>

????????<div?id=“outB”?style=“height:200;?background:#0000ff;top:100px;position:relative;”>

????????????<div?id=“outC”?style=“height:100px;?background:#FFB90F;top:50px;position:relative;”>div>

????????div>

????div>

body>

當點擊outC的時候,之后打印出capture-->target,不會打印出bubble。因為當事件傳播到outC上的處理函數時,通過stopPropagation阻止了事件的繼續傳播,所以不會繼續傳播到冒泡階段。

最后再看一段更有意思的代碼:

<script>window.onload?=?function(){var?outA?=?document.getElementById("outA");?var?outB?=?document.getElementById("outB");?var?outC?=?document.getElementById("outC");?//?目標
?outC.addEventListener('click',function(event){alert("target");},false);//?事件冒泡
?outA.addEventListener('click',function(){alert("bubble");},false);//?事件捕獲
?outA.addEventListener('click',function(){alert("capture");event.stopPropagation();},true);?
?};script>



<body>

????<div?id="outA"?style="width:400px;?height:400px;?background:#CDC9C9;position:relative;">

????????<div?id="outB"?style="height:200;?background:#0000ff;top:100px;position:relative;">

????????????<div?id="outC"?style="height:100px;?background:#FFB90F;top:50px;position:relative;">div>?

????????div>

????div>

body>

執行結果是只打印capture,不會打印target和bubble。神奇吧,我們點擊了outC,但是卻沒有觸發outC上的事件處理函數,而是觸發了outA上的事件處理函數。原因不做解釋,如果你還不明白,可以再讀一遍本文章。

*聲明:本文于網絡整理,版權歸原作者所有,如來源信息有誤或侵犯權益,請聯系我們刪除或授權事宜。

公眾號ID:tzbc666掃碼關注最新動態點個好看和轉發也是一種支持喲!

總結

以上是生活随笔為你收集整理的addeventlistener事件第三个参数_简析JavaScript 事件绑定、事件冒泡、事件捕获和事件执行顺序...的全部內容,希望文章能夠幫你解決所遇到的問題。

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

主站蜘蛛池模板: 中国黄色网页 | 明星双性精跪趴灌满h | 果冻av在线 | av动漫在线免费观看 | 精品婷婷 | 成人国产精品久久久 | 男女视频一区 | 97视频总站 | 疯狂做受xxxx国产 | 欧美一级爱爱视频 | 狠狠操狠狠插 | 日本香蕉视频 | 黄色激情视频在线观看 | 亚洲国产综合视频 | 91精品国产综合久久久密臀九色 | 亚洲精品久久久狠狠狠爱 | 亚洲av无码一区二区三区人 | 亚洲福利社区 | 91精品国产自产在线观看 | 色屁屁影院www国产高清麻豆 | aaa成人 | heyzo国产| 免费网站污 | 99re在线观看| 亚洲国产一二三 | 成年人www| 亚洲国产精品第一页 | 99免费在线观看视频 | 成人精品久久久午夜福利 | jizz国产免费 | 成人午夜精品一区二区 | 进去里在线观看 | 精品欧美一区二区三区免费观看 | 色婷婷av国产精品 | 久久av无码精品人妻系列试探 | 久久精品23| 久草福利在线 | 亚洲成人精品一区 | 好色999| 成人依依| 日本亲子乱子伦xxxx50路 | heyzo北岛玲在线播放 | 性久久久久久久久 | 欧美激情成人网 | 一级v片 | 视频在线观看一区 | 中文字幕日韩精品一区 | 51妺嘿嘿午夜福利 | 天天欲色 | 九九热在线精品视频 | 国语对白真实视频播放 | 打开每日更新在线观看 | 亚洲av无码成人精品国产 | 麻豆md0077饥渴少妇 | 殴美毛片| 按摩ⅹxxx性hd中国 | 一区福利视频 | 国产成人精品av | 精品黑人一区二区三区国语馆 | 国产在线拍揄自揄拍无码 | 欧美淫视频 | 欧美精品人妻一区二区 | 国产xxxx在线观看 | 天天想你在线观看完整版电影免费 | 成人免费在线观看 | 神马久久久久 | 波多野结衣不卡视频 | 国产3级在线 | 欧美骚少妇| 成年人网站黄 | 2020亚洲天堂 | 日日免费视频 | 婷婷成人av | 美国特色黄a大片 | 国产精品久久久久久久天堂 | 妓院一钑片免看黄大片 | 四虎成人在线观看 | 欧美成人精品欧美一级乱 | 青青久久久 | 久久亚洲综合国产精品99麻豆精品福利 | 欧美视频免费看 | 福利视频免费看 | 一区二区成人精品 | 日本一区二区三区免费看 | 人妻内射一区二区在线视频 | 婷婷成人av | 久久精品影视 | 日韩欧美一区视频 | 日韩中文字幕精品 | 超碰美女在线 | 日韩少妇一区二区 | 日本一级视频 | 小泽玛利亚一区二区三区视频 | 三级a视频 | a在线观看免费 | 国产一区在线免费观看 | 熟女少妇内射日韩亚洲 | 欧美一区二区视频在线 | 色播五月综合 |