淺談js之事件流

這些日子我就把js的相關知識梳理一下,今天來講javascript中的事件流。javascript

1.事件流css

事件流:從頁面中接收事件的順序。也就是說當一個事件產生時,這個事件的傳播過程,就是事件流。html

  • IE的事件流

  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事件流再一塊說明;

  • 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>
DOM事件流代碼

代碼有點多見諒了!也是爲了最能說明問題!

打印是這樣的:

這是我點擊最裏面DIV兒子元素所發生的情形,能夠看出捕獲階段也能觸發目標元素上的事件,而不單單是在冒泡階段;而且仍是從window開始,到最後再以window對象結束,瀏覽器廠商就是任性,不把W3c看在眼裏。你的標準我想實現就實現不想就不實現;

當我把DIV爺爺的事件綁定方式換成DOM0級的方式,其餘的保持不變,即

grandparent.onclick = function() {
    console.log("我是在哪一個階段發生呢?")
  }

是這樣打印的

再次說明了我上面在IE事件流中強調的,用DOM0級綁定事件時,事件只發生冒泡的階段;

有時咱們想要事件流,有時不想要,想要還好說,不想要怎麼辦呢?怎麼阻止冒泡,和捕獲。這個等到咱們講事件對象(event)時再說;

相關文章
相關標籤/搜索