談談js點擊以後發生了什麼

前言

    之因此忽然想寫這個文章,主要是以前看到一篇有意思的博文,《探究點擊事件在JavaScript事件循環中的表現》,有趣的地方在於JS點擊事件加入回調的並非點擊事件的回調方法,而是點擊事件描述(點擊位置等描述點擊的)es6

點擊不是加入回調而不是加入事件描述

<body style="height: 2000px">
    <button class="a">打開控制檯,快速點擊三次</button>
    <br />
    <button class="b" style="height: 1000px;width: 1000px">按鈕b</button>
    <script>
      var btn = document.querySelector(".a");
      btn.onclick = function() {
        console.log("click a");
        setTimeout(function() {
          //頁面失去響應2s。
          var time = new Date().getTime();
          while (new Date().getTime() - time < 2000) {}
          window.scrollTo(100, 500); //滾動到第二個按鈕上。
          console.log("timeout");
        });
      };

      var btn1 = document.querySelector(".b");
      btn1.onclick = function() {
        console.log("click b");
      };
    </script>
  </body>
複製代碼

當咱們連續點擊button.a兩次的時候,結果倒是bash

click a
timeout
click b
複製代碼

明明是點擊的button.a,爲何會觸發button.b的事件?dom

    可見,點擊並無直接把回調推入事件循環(對事件循環不瞭解,能夠先去了解一下)的,而是推入了點擊事件的描述(推測就是點擊位置、事件類型...),當咱們觸發點擊的時候,js會去點擊位置尋找相應的事件,在上面的例子中,咱們在點擊button.a以後執行了一個setTimeout滾動頁面到button.b的位置,以後執行第二次點擊的事件,在該位置button.a已經不見了,而是button.b,因此會執行button.b的回調事件。測試

事件機制

    不管經過onclick仍是addEventListener實現事件綁定,我懷疑綁定機制是同樣的,由於在實際測試中,我發現onclick執行順序和addEventListener是同樣的,也就是何時綁定,那麼就在第幾個執行。     addEventListeneronclick不一樣,不是直接給dom綁定屬性,而且我在dom節點上也沒有看到任何相應的對象用於保存事件,可見addEventListener是不一樣的機制,參考EventEmitter,試着去實現一個addEventListenerui

// es6的Map可使用對象做爲鍵值對的鍵值
var listeners = new Map(); // 保存dom和其對應的事件

function addEventListener(dom, type, callback) {
  if(listeners.has(dom)) {
    listeners.get(dom)[type].push(callback);
  } else {
     listeners.set(dom, {
      [type]: [callback]
     })
  }
}
// 點擊以後作了什麼
// 1. 保存事件(事件類型: 'click', 觸發位置)
...
// 2. 事件循環到觸發的時候,根據點擊
複製代碼

總結

經過上面分析,總結一下spa

點擊一個dom以後發生了什麼?.net

  1. 保存事件 向事件循環隊列中添加事件描述對象,主要是(事件類型: 'click', 觸發位置: {x:,y:},...)
  2. 事件循環到觸發 根據點擊事件描述對象去dom樹中找到該dom(不在意是否是點擊的那個,只是當前該位置的dom)
  3. 執行 經過listeners找到該dom對應的回調,而且執行
相關文章
相關標籤/搜索