事件

前言

前段時(shí)間在周會(huì)上被迫分享了一些 JavaScript 基礎(chǔ)知識(shí),后來(lái)聽小伙伴反饋,組織性和邏輯性太亂,今天自己特意翻了下書本(JavaScript高級(jí)程序設(shè)計(jì)),以下是閱讀后的整理,以便后續(xù)溫故知新。

嗯,今天的主角是事件

事件

定義

以我的理解,事件就是指一系列的動(dòng)作,像我們經(jīng)常接觸的click、dbclick以及鍵盤的keydown、keyup或者還有一些文檔(DOM)的加載、圖片的加載,焦點(diǎn)事件等等。其實(shí)事件的主要目的就是為了JavaScriptHTML更好的交互。

課本上的定義是:

事件,就是文檔或?yàn)g覽器窗口中發(fā)生的一些特定的交互瞬間

事件流

事件流是事件中一個(gè)重要的概念,由于歷史(IE與Netscape巴拉巴拉~)的原因,出現(xiàn)了兩種完全相反的事件流概念。

首先看下事件流的定義:

事件流是描述頁(yè)面接收事件的順序

顧名思義,事件流就是指事件的流向嘛,這個(gè)很好理解。前面說兩位爸爸提出了兩個(gè)截然相反事件流概念,是啥呢?我想大家都應(yīng)該有聽過 事件捕獲和事件冒泡

事件捕獲

直接上圖:


image.png

舉個(gè)例子

<html>
  <body>
    <div>今晚該點(diǎn)我了,小哥!</div>
  </body>
</html>

單擊div元素,click將會(huì)以以下順序發(fā)生:

  1. document
  2. html
  3. body
  4. div

注意:
1.IE9一下不支持事件捕獲;
2.DOM2級(jí)規(guī)范要求事件從document對(duì)象開始傳播,但瀏覽器多數(shù)都是從window對(duì)象開始傳播

事件冒泡

首先,說個(gè)重點(diǎn)因?yàn)闉g覽器兼容性問題,早期(IE9之前)是不支持事件捕獲的,所以建議使用時(shí)間冒泡處理事件

上圖


image.png

同樣的代碼(時(shí)間捕獲的代碼)

事件的順序剛好相反:

  1. div
  2. body
  3. html
  4. document
DOM事件流

DOM2級(jí)事件 規(guī)定事件流包括3個(gè)階段

  1. 事件捕獲階段
  2. 目標(biāo)階段
  3. 時(shí)間冒泡階段

在DOM事件流中,實(shí)際的目標(biāo)(div)在捕獲階段是不會(huì)接收到事件的,這意味著事件從documen->html->body就停止了。在事件處理中,將"處于目標(biāo)階段"看做是冒泡階段的一部分。

但是,多數(shù)支持DOM2事件流的現(xiàn)代瀏覽器都實(shí)現(xiàn)了在捕獲階段觸發(fā)事件對(duì)象上的事件,so~

以上是書本原話,大家自行體會(huì)。

注意,IE9以下是不支持DOM2級(jí)事件流的

事件處理程序

用來(lái)響應(yīng)某個(gè)事件的函數(shù)叫做事件處理程序(或事件偵聽器

為事件指定處理程序的方式有以下幾種:

  1. HTML事件處理程序
  2. DOM0級(jí)時(shí)間處理程序
  3. DOM2級(jí)事件處理程序
  4. IE事件處理程序
HTML 事件處理程序

看代碼

  • 方法一
<input type='button' value='Click me' onclick='alert(123)' />
  • 方法二
<script>
  function showMessage(){
    console.log(123);
  }
</script>
<input type='button' value='Click me' onclick='showMessage()' />

這兩種注冊(cè)事件的方式,大家應(yīng)該都不陌生,需要一提的是在方法一中,代碼部分(alert(123))是作為JavaScript代碼來(lái)處理的且是嵌套在html代碼中的,如果代碼中包含未經(jīng)過轉(zhuǎn)義的HTMl語(yǔ)法字符是有問題的,所以請(qǐng)轉(zhuǎn)義OR用第二種方法。

代碼執(zhí)行時(shí)的作用域問題
  • 在代碼執(zhí)行時(shí)以上兩種方法都有權(quán)訪問全局作用域中的任何代碼
  • 當(dāng)前的this指向目標(biāo)元素

作用域擴(kuò)展
看實(shí)例代碼:JSFiddeler代碼示例

代碼截圖


作用域擴(kuò)展.png

  • 在函數(shù)內(nèi)部,你可以像訪問局部變量一樣訪問document及該元素本身的成員
  • 如果當(dāng)前元素是一個(gè)表單的輸入元素,則作用域中還會(huì)包含訪問表單元素(父元素)的入口,這樣可以更快的訪問表單字段。
HTML事件處理程序的缺點(diǎn)
  • 時(shí)差問題,當(dāng)事件觸發(fā)時(shí),事件處理程序可能尚不具備執(zhí)行條件
    舉個(gè)例子,前面的showMessage如果在按鈕的下方,用戶點(diǎn)擊按鈕時(shí),showMessage還未加載完畢就會(huì)出現(xiàn)錯(cuò)誤
  • 作用域鏈可能因?yàn)闉g覽器的的不同產(chǎn)生差異
  • HTML代碼和JavaScript代碼緊密耦合
DOM0 級(jí)時(shí)間處理程序

先說優(yōu)點(diǎn)

  1. 簡(jiǎn)單
  2. 兼容性非常好,具有跨瀏覽器的優(yōu)勢(shì)

看看如何注冊(cè)

var btn = document.getElementById('mybtn');
btn.onclick = function(){
  console.log('clicked');
}

嗯,簡(jiǎn)單不需要多說什么。

幾點(diǎn)需要注意的

  • 處理程序中this指向當(dāng)前元素
  • 該種方式添加的事件處理程序都是在事件流的冒泡階段被處理的
  • 當(dāng)btn.onclick=null時(shí),可以去除事件綁定(有好處,日后展開)
DOM2 級(jí)處理程序

DOM2級(jí)事件定義了兩個(gè)方法,用來(lái)處理和刪除事件處理程序addEventListener()、removeEventListener();所有實(shí)現(xiàn)DOM2級(jí)規(guī)范的dom節(jié)點(diǎn)都包含這兩個(gè)方法;這兩個(gè)函數(shù)有三個(gè)參數(shù),依次順序分別是:要處理的事件名稱(click,load)、處理函數(shù)、以及一個(gè)布爾值。最后這個(gè)布爾值如果是true表示在捕獲階段調(diào)用時(shí)間處理程序,否則在冒泡階段調(diào)用。

看代碼

var btn = document.getElementById('mybtn');
btn.addEventListener('click',function(){
  console.log(1111);
},true);

如果需要將事件處理程序移除,必須使用有簽名的處理函數(shù),上述代碼的匿名函數(shù)則無(wú)法移除`

btn.removeEventListener("click",handler,true)

優(yōu)點(diǎn)

  • 可以添加多個(gè)處理程序
  • 解耦

福利:查看代碼 ,可以稍稍理解下這里的捕獲階段調(diào)用事件處理程序和冒泡階段調(diào)用是啥意思

IE處理程序

說實(shí)話,我個(gè)人是不太想說這個(gè)的,因?yàn)樗鼤?huì)讓人混亂,我建議還是先了解標(biāo)準(zhǔn)之后再來(lái)閱讀這個(gè)比較好。但為了知識(shí)的連貫性,我還是大概說一下下。

IE早期的版本(我試了ie11好像已經(jīng)去除了,估計(jì)還是ie9之前,具體沒有找到資料)中實(shí)現(xiàn)了類似DOM2中的兩個(gè)方法attachEvent、detachEvent。

以下列舉這兩個(gè)方法的不同

  • 因?yàn)镮E8及更早的版本只支持時(shí)間冒泡,so 通過該方法注冊(cè)的事件處理程序都會(huì)被添加到冒泡階段
  • 看下代碼
      btn.attachEvent('onclick',handler)
    
    多了個(gè) on
  • this指向window
  • 注冊(cè)了的多個(gè)處理程序的執(zhí)行順序和DOM2順序相反,DOM2是先注冊(cè)的先執(zhí)行

跨瀏覽器的事件處理程序

var EventUtil = {
  addHandler : function(element, type, handler){
    if(element.addEventListener){
      element.addEventListener(type,handler,false);
    }else if(element.attachEvent){
      element.attachEvent('on' + type, handler)
    }else{
      element['on' + type] = handler;
    }
  },
  removeHandler : function(element,type,handler){
    if(element.removeEventListener){
      element.removeEventListener(type,handler,false);
    }else if(element.detachEvent){
      element.detachEvent('on'+type,handler);
    }else{
      element['on' + type] = null;
    }
  }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • JavaScript 程序采用了異步事件驅(qū)動(dòng)編程模型。在這種程序設(shè)計(jì)風(fēng)格下,當(dāng)文檔、瀏覽器、元素或與之相關(guān)的對(duì)象發(fā)...
    劼哥stone閱讀 1,333評(píng)論 3 11
  • 一、問答 1. dom對(duì)象的innerText和innerHTML有什么區(qū)別? innerHTML: 也就是從對(duì)象...
    饑人谷_羅偉恩閱讀 699評(píng)論 0 2
  • 本章內(nèi)容 理解事件流 使用事件處理程序 不同的事件類型 JavaScript 與 HTML 之間的交互是通過事件實(shí)...
    悶油瓶小張閱讀 334評(píng)論 0 0
  • 聲明:本文來(lái)源于http://www.webzsky.com/?p=731我只是在這里作為自己的學(xué)習(xí)筆記整理一下(...
    angryyan閱讀 7,247評(píng)論 1 6
  • 事件流 事件流描述的是從頁(yè)面中接收事件的順序。但有意思的是,IE 和 Netscape 開發(fā)團(tuán)隊(duì)居然提出了差不多是...
    More_5897閱讀 273評(píng)論 0 1

友情鏈接更多精彩內(nèi)容