摘要:目標階段真正點擊的元素的事件發生了兩次,因為在上面的代碼中,既在捕獲階段綁定了事件,又在冒泡階段綁定了事件,所以發生了兩次。所以很明顯用直接綁定的事件發生在了冒泡階段。
如果對事件大概了解,可能知道有事件冒泡這回事,但是冒泡、捕獲、傳播這些機制可能還沒有深入的研究實踐一下,我抽時間整理了一下相關的知識。
本文主要對事件機制一些細節進行討論,過于基礎的事件綁定知識方法沒有介紹。
特別少的篇幅關注瀏覽器兼容問題,畢竟原理了解了,兼容性問題可以自己想辦法解決了。
在瀏覽器相對標準化之前,各個瀏覽器廠商都是自己實現的事件模型,有的用了冒泡,有的用了捕獲,W3C為了兼顧之前的標準,將事件發生定義成如下三個階段:
1、捕獲階段
2、目標階段
3、冒泡階段
只是硬生生的說事件機制到底是怎么回事不容易理解,用一個demo為主線說明事件的原理比較容易理解:
HTML
wrapDivinnerP textSpan
CSS
JavaScript
demo頁面效果圖
這個時候,如果點擊一下textSpan這個元素,控制臺會打印出這樣的內容:
當按下鼠標點擊后,到底發生了什么的,現在我基于上面的例子來說一下:
capture=>start: 捕獲階段開始 window=>operation: window document=>operation: document documentElement=>operation: documentElement body=>operation: body wrapDiv=>operation: wrapDiv innerP=>operation: innerP target=>start: 捕獲階段結束,目標階段開始 textSpan=>operation: textSpan textSpan2=>operation: textSpan bubble=>start: 目標階段結束,冒泡階段開始 innerP2=>operation: innerP wrapDiv2=>operation: wrapDiv body2=>operation: body documentElement2=>operation: documentElement document2=>operation: document window2=>operation: window bubbleend=>start: 冒泡階段結束 capture->window->document->documentElement->body->wrapDiv->innerP->target->textSpan->textSpan2->bubble->innerP2->wrapDiv2->body2->documentElement2->document2->window2->bubbleend
從上面所畫的事件傳播的過程能夠看出來,當點擊鼠標后,會先發生事件的捕獲
捕獲階段:首先window會獲捕獲到事件,之后document、documentElement、body會捕獲到,再之后就是在body中DOM元素一層一層的捕獲到事件,有wrapDiv、innerP。
目標階段:真正點擊的元素textSpan的事件發生了兩次,因為在上面的JavaScript代碼中,textSapn既在捕獲階段綁定了事件,又在冒泡階段綁定了事件,所以發生了兩次。但是這里有一點是需要注意,在目標階段并不一定先發生在捕獲階段所綁定的事件,而是先綁定的事件發生,一會會解釋一下。
冒泡階段:會和捕獲階段相反的步驟將事件一步一步的冒泡到window
那可能有一個疑問,我們不用addEventListener綁定的事件會發生在哪個階段呢,我們來一個測試,順便再演示一下我在上面的目標階段所說的目標階段并不一定先發生捕獲階段所綁定的事件是怎么一回事。
我們重新改一下JavaScript代碼:
再看控制臺的結果:
target和currentTarget圖中第一個被圈出來的解釋:textSpan是被點擊的元素,也就是目標元素,所有在textSpan上綁定的事件都會發生在目標階段,在綁定捕獲代碼之前寫了綁定的冒泡階段的代碼,所以在目標元素上就不會遵守先發生捕獲后發生冒泡這一規則,而是先綁定的事件先發生。
圖中第二個被圈出來的解釋:由于wrapDiv不是目標元素,所以它上面綁定的事件會遵守先發生捕獲后發生冒泡的規則。所以很明顯用onclick直接綁定的事件發生在了冒泡階段。
上面的代碼中寫了e.target和e.currentTarget,還沒有說是什么,target和currentTarget都是event上面的屬性,target是真正發生事件的DOM元素,而currentTarget是當前事件發生在哪個DOM元素上。
可以結合控制臺打印出來的信息理解下,目標階段也就是 target == currentTarget的時候。我沒有打印它們兩個因為太長了,所以打印了它們的nodeName,但是由于window沒有nodeName這個屬性,所以是undefined。
說到事件,一定要說的是如何阻止事件傳播。總是有很多帖子說e.stopPropagation()是阻止事件的冒泡的傳播,實際上這么說并不是很準確,因為它不僅可以阻止事件在冒泡階段的傳播,還能阻止事件在捕獲階段的傳播。
來看一下我們再改一下的JavaScript代碼:
我們在事件的捕獲階段阻止了傳播,看一下控制臺的結果:
實際上我們點擊的是textSpan,但是由于在捕獲階段事件就被阻止了傳播,所以在textSpan上綁定的事件根本就沒有發生,冒泡階段綁定的事件自然也不會發生,因為阻止事件在捕獲階段傳播的特性,e.stopPropagation()很少用到在捕獲階段去阻止事件的傳播,大家就以為e.stopPropagation()只能阻止事件在冒泡階段傳播。
e.preventDefault()可以阻止事件的默認行為發生,默認行為是指:點擊a標簽就轉跳到其他頁面、拖拽一個圖片到瀏覽器會自動打開、點擊表單的提交按鈕會提交表單等等,因為有的時候我們并不希望發生這些事情,所以需要阻止默認行為,這塊的知識比較簡單,可以自己去試一下。
與事件相關的兼容性問題這里只是簡單提一下兼容性問題,不做過多的展開。對于綁定事件,ie低版本的瀏覽器是用attachEvent,而高版本ie和標準瀏覽器用的是addEventListener,attachEvent不能指定綁定事件發生在捕獲階段還是冒泡階段,它只能將事件綁定到冒泡階段,但是并不意味這低版本的ie沒有事件捕獲,它也是先發生事件捕獲,再發生事件冒泡,只不過這個過程無法通過程序控制。
其實事件的兼容性問題特別的多,比如獲取事件對象的方式、綁定和解除綁定事件的方式、目標元素的獲取方式等等,由于古老的瀏覽器終究會被淘汰,不過多展開了。
歡迎關注【本期節目】,微信公眾號ID:benqijiemu。
這里有:互聯網思考、軟件&工具推薦、前端技術等。
可以在公眾號回復我,希望和大家一起交流所有與互聯網相關的事情~
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/85903.html
摘要:取消事件的默認行為。阻止事件的派發包括了捕獲和冒泡阻止同一個事件的其他監聽函數被調用。 事件模型 DOM0 級事件模型 -沒有事件流,這種方式兼容所有瀏覽器 // 方式一 將事件直接通過屬性綁定在元素上 / 方式二 獲取到頁面元素后,通過 onclick 等事件,將觸發的方法指定為元素的事件 var btn = document.getElementById(btn) btn....
摘要:響應某個事件的函數就叫事件處理程序或事件偵聽器。為事件指定事件處理程序的方法主要有種。事件處理程序事件直接加在元素上。事件委托利用冒泡的原理,把事件加到父元素或祖先元素上,觸發執行效果,解決事件處理程序過多問題。事件委托優點提高性能。 JavaScript簡單入門可以看看我丑丑的Github博客JavaScript簡單入門 事件 JavaScript與HTML之間的交互是通過事件實現的...
摘要:布爾值表示捕獲階段調用事件處理程序,表示冒泡階段通過對象的方法,也可以定義事件的回調函數。對象會被作為第一個參數傳遞給事件監聽的回調函數。布爾默認值是,當設置成時用以取消事件的默認行為與中的相同。 其實這篇文章挺早之前就寫了,但是由于sf保存方面的bug,所以當時寫了一大堆,結果沒保存,覺得這個沒寫完是個不小的遺憾,今天正好有空,就給補充下了,也正好給我的javascript學習總結做...
閱讀 1399·2021-09-02 09:53
閱讀 2667·2021-07-29 13:50
閱讀 1715·2019-08-30 11:07
閱讀 1571·2019-08-30 11:00
閱讀 1450·2019-08-29 14:00
閱讀 1844·2019-08-29 12:52
閱讀 2560·2019-08-29 11:11
閱讀 3415·2019-08-26 12:23