帶你快速理解javascript中的事件模型
javascript中有兩種事件模型:DOM0,DOM2。而對于這兩種的時間模型,我一直不是非常的清楚,現(xiàn)在通過網(wǎng)上查閱資料終于明白了一些。
一. DOM0級事件模型
DOM0級事件模型是早期的事件模型,所有的瀏覽器都是支持的,而且其實現(xiàn)也是比較簡單。代碼如下:
<p id = 'click'>click me</p> <script> document.getElementById('click').onclick = function(event){ alert(event.target); } </script>
這種事件模型就是直接在dom對象上注冊事件名稱,這段代碼就是在p標(biāo)簽上注冊了一個onclick事件,在這個事件函數(shù)內(nèi)部輸出點擊的目標(biāo)。而解除事件則更加簡單,就是將null復(fù)制給事件函數(shù),如下:
document.getElementById('click'_).onclick = null;
由此我們可以知道dom0中,一個dom對象只能注冊一個同類型的函數(shù),因為注冊多個同類型的函數(shù)的話,就會發(fā)生覆蓋,之前注冊的函數(shù)就會無效。
var click = document.getElementById('click'); click.onclick = function(){ alert('you click the first function'); }; click.onclick = function(){ alert('you click the second function') }
在這段代碼中,我們?yōu)閐om對象注冊了兩個onclick函數(shù),但是結(jié)果是只執(zhí)行了第二個注冊的函數(shù),前面所注冊的函數(shù)被覆蓋了。
二. DOM2級事件模型
1. 事件捕獲和事件冒泡(capture,bubble)
首先,IE8及以下是不支持這種事件模型的。事件捕獲和事件冒泡的機(jī)制如下圖:
如上圖所示,123代表事件捕獲,4567代表事件冒泡。首先我們使用下面的代碼:
<div id = 'outer' style = 'margin: 100px 0 0 100px; width: 200px;height: 200px; background: red;'> <div id="inner" style = 'margin-left:20px; width: 50px;height:50px; background: green;'></div> </div>
假設(shè)我們點擊了ID為inner的div,那么此時的事件流程就是,首先執(zhí)行捕獲階段:document-html-body-div(outer)。然后執(zhí)行冒泡階段:div(inner)-div(outer)-body-html-document。
2. DOM2級的注冊事件和解除事件
在DOM2級中使用addEventListener和removeEventListener來注冊和解除事件(IE8及之前版本不支持)。這種函數(shù)較之之前的方法好處是一個dom對象可以注冊多個相同類型的事件,不會發(fā)生事件的覆蓋,會依次的執(zhí)行各個事件函數(shù)。
addEventListener('事件名稱','事件回調(diào)','捕獲/冒泡')。示例如下:
<div id = 'outer' style = 'margin: 100px 0 0 100px; width: 200px;height: 200px; background: red;'> <div id="inner" style = 'margin-left:20px; width: 50px;height:50px; background: green;'></div> </div> <script> var click = document.getElementById('inner'); click.addEventListener('click',function(){ alert('click one'); },false); click.addEventListener('click',function(){ alert('click two'); },false); </script>
首先我們要知道addEventListenr的第一個參數(shù)是事件名稱,與DOM0級不同的是沒有”on“,另外第三個參數(shù)代表捕獲還是冒泡,true代表捕獲事件,false代表冒泡事件。
而在這段代碼中,我們?yōu)閕nner的div注冊了兩個click事件函數(shù),結(jié)果是瀏覽器會依次執(zhí)行這兩個函數(shù)。
下面我們演示如何使用事件流的發(fā)生機(jī)制。
<div id = 'outer' style = 'margin: 100px 0 0 100px; width: 200px;height: 200px; background: red;'> <div id="inner" style = 'margin-left:20px; width: 50px;height:50px; background: green;'></div> </div> <script> var click = document.getElementById('inner'); var clickouter = document.getElementById('outer'); click.addEventListener('click',function(){ alert('inner show'); },true); clickouter.addEventListener('click',function(){ alert('outer show'); },true); </script>
這段代碼,我們使用了捕獲事件,由于inner是嵌套在outer中的,所以我們知道當(dāng)使用捕獲的時候outer是應(yīng)該首先捕獲到這個事件的,其次inner才能捕獲到這個事件。那么結(jié)果就是outer首先執(zhí)行,其次是inner執(zhí)行。
那么我把outer的執(zhí)行時機(jī)改為冒泡的階段呢?
alickouter.addEventListener('click',function(){ alert('outer show'); },false);
這種情況下,就是先執(zhí)行inner后執(zhí)行outer了。同理我們把二者的事件執(zhí)行時機(jī)都改為冒泡階段的話,依舊是先執(zhí)行inner后執(zhí)行outer。那么還有個問題,就是如果我們把inner注冊兩個click事件,一個是在捕獲階段,另一個是在冒泡階段,也就是說把a(bǔ)ddEventListenter的第三個參數(shù)分別設(shè)置為false和true,那么執(zhí)行的順序又是怎樣的呢。
<script> var click = document.getElementById('inner'); var clickouter = document.getElementById('outer'); click.addEventListener('click',function(){ alert('capture show'); },true); click.addEventListener('click',function(){ alert('bubble show'); },false); </script>
這種情況下首先這些的是capture show,其次是bubble show。但是這種結(jié)果是與注冊的順序有關(guān)系的,先注冊就先執(zhí)行。因為我們在看事件捕獲和事件冒泡示意圖,發(fā)現(xiàn)最后具體的dom對象是只有一個的。
那么 如果我們給outer和inner都注冊了click事件但是我不希望outer執(zhí)行怎么辦呢?這個時候我們就需要用到stopPropagation函數(shù)了,這個函數(shù)是用來阻止冒泡,言下之意是讓事件不再繼續(xù)冒泡下去,這樣接下來注冊同樣類型事件的dom對象就不會執(zhí)行了。
比如在自制下拉框的時候,我們點擊瀏覽器的其他位置,我們需要下拉框的options隱藏,這時我們就要用到stopPropagation了。如下:
<script> var click = document.getElementById('inner'); var clickouter = document.getElementById('outer'); click.addEventListener('click',function(event){ alert('inner show'); event.stopPropagation(); },false); clickouter.addEventListener('click',function(){ alert('outer show'); },false); </script>
正常的情況下,我們在不添加stopPropagation函數(shù)時,首先應(yīng)該執(zhí)行inner,然后執(zhí)行outer,但是當(dāng)我們在inner的事件函數(shù)中添加了stopPropagation函數(shù)之后,執(zhí)行完inner的事件函數(shù)之后,就不會在執(zhí)行outer的事件函數(shù)了,也可以理解為事件冒泡到inner之后就消失了,因此也就不會在執(zhí)行接下來的事件函數(shù)了。
由于事件捕獲階段沒有可以阻止事件的函數(shù),所以一般都是設(shè)置為事件冒泡。
好了以上就是全部內(nèi)容啦 ,希望對大家的學(xué)習(xí)有所幫助~~
相關(guān)文章
javascript學(xué)習(xí)筆記(三)BOM和DOM詳解
本文應(yīng)用了很多實例,來解讀JavaScript中BOM和DOM,DOM是一個使程序和腳本有能力動態(tài)地訪問和更新文檔的內(nèi)容、結(jié)構(gòu)以及樣式的平臺和語言中立的接口。,而BOM定義了JavaScript可以進(jìn)行操作的瀏覽器的各個功能部件的接口。2014-09-09script標(biāo)簽屬性用type還是language
本文介紹了javascript腳本中標(biāo)簽屬性type與language的區(qū)別分析,有需要的小伙伴可以參考下2015-01-01javascript中的對象和數(shù)組的應(yīng)用技巧
javascript中的對象和數(shù)組的應(yīng)用技巧...2007-01-01一篇文章帶你搞懂JavaScript的變量與數(shù)據(jù)類型
這篇文章主要為大家介紹了JavaScript的變量與數(shù)據(jù)類型,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-01-01全面了解JavaScript的數(shù)據(jù)類型轉(zhuǎn)換
下面小編就為大家?guī)硪黄媪私釰avaScript的數(shù)據(jù)類型轉(zhuǎn)換。小編覺得挺不錯的,現(xiàn)在就分享給大家看,也給大家做個參考。一起跟隨小編過來看看吧2016-07-07JavaScript實現(xiàn)的GBK、UTF8字符串實際長度計算函數(shù)
這篇文章主要介紹了JavaScript實現(xiàn)的GBK、UTF8字符串實際長度計算函數(shù),需要的朋友可以參考下2014-08-08