這些日子我就把js的相關知識梳理一下,今天來講javascript中的事件流。javascript
1.事件流css
事件流:從頁面中接收事件的順序。也就是說當一個事件產生時,這個事件的傳播過程,就是事件流。html
IE中的事件流叫事件冒泡;事件冒泡:事件開始時由最具體的元素接收,而後逐級向上傳播到較爲不具體的節點(文檔)。對於html來講,就是當一個元素產生了一個事件,它會把這個事件傳遞給它的父元素,父元素接收到了以後,還要繼續傳遞給它的上一級元素,就這樣一直傳播到document對象(親測如今的瀏覽器到window對象,只有IE8及下不這樣);java
再多說一句,如今的瀏覽器默認是採用的是事件冒泡;在DOM0級方法綁定事件只能是事件冒泡,不能設置;在DOM2級你能夠設置是用事件冒泡仍是事件捕獲(下面說);chrome
說了半天冒泡有可能沒太聽懂,上代碼就知道了:瀏覽器
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>事件冒泡</title> <style type="text/css"> #child{ background: red; width:50px; height:50px; } #father{ width:100px; height:100px; background:green; } #grandparent{ width:150px; height:150px; background:black; margin:100px auto 0; } </style> </head> <body> <div id='grandparent'> <div id='father'> <div id='child'></div> </div> </div> </body> <script type="text/javascript"> var grandparent = document.getElementById("grandparent"); var parent = document.getElementById("father"); var child = document.getElementById('child'); var html = document.getElementsByTagName("html")[0]; var body = document.body; child.onclick = function () { console.log("我是兒子"); } parent.onclick = function () { console.log("我是父親"); } grandparent.onclick = function () { console.log("我是爺爺"); } window.onclick = function () { console.log("我是window"); } document.onclick = function () { console.log("我是document"); } html.onclick = function () { console.log("我是html"); } body.onclick = function () { console.log("我是body"); } </script> </html>
當我點擊紅色部分ide
會打印這樣:測試
我測試了(PS:我用的都是最新版的)chrome,firefox,opera,IE11,IE10,IE9都是這個結果,也就是說如今都冒泡到window對象,不單單是到document對象,可是IE8及以前的就冒泡到document就結束了;spa
這就是事件冒泡,它會把你這個click事件,一級一級的向上傳遞,若是相應的元素也綁定click事件處理程序(這裏強調是click事件,若是你是給綁定了其它事件,那沒用),那麼它的這個事件處理程序也會執行,也就產生了上面的結果了;firefox
形象的就是跟水裏的魚吐泡泡似的,慢慢的向上傳遞;
事件捕獲是網景(Netscape)提出來的,事件捕獲是不太具體的元素應該更早接受到事件,而最具體的節點應該最後接收到事件。他們的用意是在事件到達目標以前就捕獲它;也就是跟冒泡的過程正好相反,以html的click事件爲例,document對象(DOM級規範要求從document開始傳播,可是如今的瀏覽器是從window對象開始的)最早接收到click事件的而後事件沿着DOM樹依次向下傳播,一直傳播到事件的實際目標;我測試了一下(我用的都是最新的瀏覽器),chrome,opera,firefox,IE11到IE9都支持事件捕獲。
代碼等着我在下面講DOM事件流再一塊說明;
DOM2級中規定了事件流要包括三個階段:事件捕獲階段、處於目標階段、事件冒泡階段。這是W3C採用了他們兩家的事件監聽機制。(說點題外話,w3c中的不少標準就是這樣,瀏覽器廠商有不少本身的私有解決問題方式,好用的就被W3c採納了)DOM2級還規定,實際發生事件的元素在捕獲階段不能接收到事件。咱們就以上面的事件冒泡時的代碼說明這個過程:按照標準是這樣的,當一個元素產生了事件,事件是從document到html再到body再到DIV爺爺再到DIV爸爸,這時候捕獲階段就應該中止了,再進入下一個階段「處於目標階段」,而後是從DIV爸爸到DIV爺爺再到body再到html再到document,這就是事件冒泡階段;實際上咱們把處於目標階段即第二階段看做是冒泡階段的一部分,即冒泡的開始;其實是怎麼樣的呢?先上代碼,仍是前面的代碼只是改了一下js代碼:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>事件冒泡</title> <style type="text/css"> #child{ background: red; width:50px; height:50px; } #father{ width:100px; height:100px; background:green; } #grandparent{ width:150px; height:150px; background:black; margin:100px auto 0; } </style> </head> <body> <div id='grandparent'> <div id='father'> <div id='child'></div> </div> </div> </body> <script type="text/javascript"> var grandparent = document.getElementById("grandparent"); var parent = document.getElementById("father"); var child = document.getElementById('child'); var html = document.getElementsByTagName("html")[0]; var body = document.body; grandparent.addEventListener("click",function () { console.log("I am capturing grandparent"); },true); grandparent.addEventListener("click",function () { console.log("I am grandparent"); },false); parent.addEventListener("click",function() { console.log("I am parent"); },false); parent.addEventListener("click",function() { console.log("I am capturing parent"); },true); child.addEventListener("click",function() { console.log("I am capturing child"); },true); child.addEventListener("click",function() { console.log("I am child"); },false); body.addEventListener("click",function() { console.log("I am body"); },false); body.addEventListener("click",function() { console.log("I am capturing body"); },true); html.addEventListener("click",function() { console.log("I am capturing html"); },true); html.addEventListener("click",function() { console.log("I am html"); },false); document.addEventListener("click",function() { console.log("I am capturing document"); },true); document.addEventListener("click",function() { console.log("I am document"); },false); window.addEventListener("click",function() { console.log("I am window"); },false); window.addEventListener("click",function() { console.log("I am capturing window"); },true); </script> </html>
代碼有點多見諒了!也是爲了最能說明問題!
打印是這樣的:
這是我點擊最裏面DIV兒子元素所發生的情形,能夠看出捕獲階段也能觸發目標元素上的事件,而不單單是在冒泡階段;而且仍是從window開始,到最後再以window對象結束,瀏覽器廠商就是任性,不把W3c看在眼裏。你的標準我想實現就實現不想就不實現;
當我把DIV爺爺的事件綁定方式換成DOM0級的方式,其餘的保持不變,即
grandparent.onclick = function() { console.log("我是在哪一個階段發生呢?") }
是這樣打印的
再次說明了我上面在IE事件流中強調的,用DOM0級綁定事件時,事件只發生冒泡的階段;
有時咱們想要事件流,有時不想要,想要還好說,不想要怎麼辦呢?怎麼阻止冒泡,和捕獲。這個等到咱們講事件對象(event)時再說;