看懂此文,不再困惑於 JS 中的事件設計

2017/04/10

原文:blog.csdn.net/aitangyong/article/details/43231111點擊文末閱讀原文即可前往

抽空學習了下javascript和jquery的事件設計,收穫頗大,總結此貼,和大家分享。

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

javascript給DOM綁定事件處理函數總的來說有2種方式:在html文檔中綁定、在js代碼中綁定。下面的方式1、方式2屬於在html中綁定事件,方式3、方式4和方式5屬於在js代碼中綁定事件,其中方法5是最推薦的做法。

方式1:

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

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

方式2:

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

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

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

}

dom.attachEvent('onclick'a);

dom.attachEvent('onclick'a);

function a

{

alert(this.id);

}

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

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

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不同。

dom.addEventListener('click' a false);

function a

{

alert(this.id);//outestA

}

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

dom.addEventListener('click' a false);

dom.addEventListener('click' a true);

function a

{

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

dom.addEventListener('click' a false);

dom.addEventListener('click' a false);

function a

{

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

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

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

方式1、方式2和方式3都不能實現事件的重複綁定,所以自然也就不存在執行順序的問題。方式4和方式5可以重複綁定特性,所以需要了解下執行順序的問題。如果你寫出依賴於執行順序的代碼,可以斷定你的設計存在問題。所以下面的順序問題,僅作為興趣探討,沒有什麼實際意義。直接上結論:addEventListener和attachEvent表現一致,如果給同一個事件綁定多個處理函數,先綁定的先執行。下面的代碼我在IE11、FF17和Chrome39都測試過。

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

(四) DOM事件流

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

DOM事件流:將事件分為三個階段:捕獲階段、目標階段、冒泡階段。先調用捕獲階段的處理函數,其次調用目標階段的處理函數,最後調用冒泡階段的處理函數。這個過程很類似於Struts2框中的action和Interceptor。當發出一個URL請求的時候,先調用前置攔截器,其次調用action,最後調用後置攔截器。

當點擊outC的時候,依次列印出capture1–>capture2–>target–>bubble2–>bubble1。到這裡是不是可以理解addEventListener(type,handler,useCapture)這個API中第三個參數useCapture的含義呢?useCapture=false意味著:將事件處理函數加入到冒泡階段,在冒泡階段會被調用;useCapture=true意味著:將事件處理函數加入到捕獲階段,在捕獲階段會被調用。從DOM事件流模型可以看出,捕獲階段的事件處理函數,一定比冒泡階段的事件處理函數先執行。

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

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

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

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

點擊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阻止事件的繼續傳播。

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

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

不是在文章評論里回復哦

本文由 一點資訊 提供 原文連結

立即按讚,感謝大大無私地分享
寫了5859808篇文章,獲得4227
Line

熱門推薦

精彩推薦

這是一個始於6月1日、終於6月3日的行業巨頭「掐架」故事。故事的主角是阿里巴巴旗下物流科技公司菜鳥網路,和國內快遞行業領軍企業順豐速運,配角包括京東、美團、騰訊雲、蘇寧、圓通、易果生鮮等,圍觀這個故事...
2月18日,武昌火車站附近發生一起惡性刑事案件,犯罪嫌疑人胡某(22歲,四川宣漢人)因口角糾紛,用極其殘忍的手段將麵館老闆姚某殺害,此事因性質惡劣,圖片極其血腥,引發大量網路輿論聚焦。目前,犯罪嫌疑人已...
75款iF金獎作品揭曉 有嚼頭!有看點! 當地時間 3 月 10 日晚 8 點,第 64 屆iF設計之夜暨頒獎禮在德國慕尼黑 BMW 世界舉行,iF 評審團揭曉了75項iF設計金獎,至此,2017 iF 設計獎所有獎項全部揭曉。 iF 設計獎...
提示:↑上方"史客兒"免費關注!● 原創投稿請至:historymook@sina.com1968年3月22日,楊成武、余立金、傅崇碧三位將軍飛來橫禍,史稱「楊余傅事件」。歷史上,余立金一直在華東地區工作,1965年調到北京,才與楊成武有...
神秘不明飛行物UFO,至今讓人無法了解其真實面目,當下互聯網上也有大量的UFO圖片及視頻,在古代不具備攝影攝像的情況下,在的一些古書上也有一些關於UFO的記載。最有名的當屬北宋科學家沈括,在其《夢溪筆談》卷...
暗網這個詞,在前段時間章瑩穎案件發生后,成了人們關注的焦點,又因為互聯網上各種文章的渲染,被蒙上了神秘和恐怖的面紗。事件的起因,是根據 FBI 調查,發現章瑩穎案件中的嫌疑人勃蘭特•克里斯坦森(Brendt Ch...
原標題:如何應對婚禮中的突發事件很多事情難以預料,婚禮現場遇到突發事件的情況也是有的,這就要求新人要提前做好應對婚禮突發事件的解決辦法,下面上海大寧福朋喜來登酒店小編就帶領大家學習一下應對婚禮突發事件...
上一期我們學習了Android中的事件處理,也詳細學習了Android中基於監聽的事件處理,同時學會了匿名內部類形式,那麼本期繼續來學習其他四種事件監聽器。一、使用內部類作為事件監聽器 和上面的匿名內部類不同,...
引言今天的直播課老師會通過js的事件機制來模仿淘寶註冊頁面表單驗證效果,實現效果如下:怎麼樣,感興趣的小夥伴抓緊入群了,獲取直播通知,觀看直播。下面給大家總結了下js中的事件講解。事件流多個彼此嵌套的...
則回覆