1. 程式人生 > >瀏覽器事件物件詳解

瀏覽器事件物件詳解

客戶端js程式採用了非同步事件驅動模型,每當我們點選或敲擊鍵盤時,瀏覽器就會產生事件,如果js程式關注特定型別的事件,那麼它可以註冊當這類事件發生時要呼叫的一個或多個處理函式。這種風格並不止應用於web程式設計,所有使用圖形使用者介面的應用程式都採用了它。它們等待事件發生,然後它們響應。
事件型別(event type)是一個用來說明發生什麼型別事件的字串,例如mouseover表示使用者移動滑鼠,keydown表示鍵盤上某個按鍵被按下。
事件目標(event target)是發生的事件或與之相關的目標。
事件處理程式(event handler)或事件監聽程式(event listener)是處理或響應事件的函式。當在特定的目標上發生特定型別的事件時,瀏覽器會呼叫對應的處理程式,當物件上註冊的事件處理程式被呼叫時,我們有這樣幾種等價的說法: 瀏覽器觸發(fire,trigger)或者派發(dispatch)了事件。
事件物件(event object)是與特定事件相關並且包含有關該事件,事件物件作為引數傳遞給事件處理函式。
事件傳播(event propagation)是瀏覽器決定哪個物件觸發其事件處理程式的過程。對於單個物件的特定事件(比如window物件的load事件),必須是不能傳播的。當文件元素上發生某個型別的事件時,他們會在文件樹上向上傳播或冒泡。有時在容器上註冊單個事件處理程式比在每個獨立的目標上都註冊處理程式要更方便。(在容器上註冊處理程式只是改變事件處理函式,並不能改變觸發的元素,觸發的元素正常都是最底層元素)。
事件傳播的另一種形式成為事件捕獲(event capturing),在容器上註冊的特定處理程式有機會在事件傳播到真實目標之前攔截它。

事件物件座標

事件物件的座標包括clientX和clientY,screenX和screenY, offsetX和offsetY,
pageX和pageY,X和Y。
clientX和clientY是相對於瀏覽器(可視區左上角的0, 0)的座標
screenX和screenY是相對於裝置螢幕左上角(0,0)的座標
offsetX和offsetY是相對於事件源左上角(0,0)的座標
pageX和pageY是相對於整個網頁左上角(0,0)的座標
X和Y 本來是IE屬性,相對於用CSS動態定位的最內層包容元素。

表單事件

當提交表單和重置表單時,< form>元素會分別觸發submit和reset事件,當用戶和類表單元素互動時,它們會發生click事件。當用戶通過輸入文字,選擇選項或選擇複選框來改變相應表單元素的狀態時,這些通常維護某種狀態的表單元素會觸發change事件。對於文字輸入域,只有使用者和表單元素完成互動並通過Tab鍵或單擊的方式移動焦點到其他焦點到其他元素上才會觸發change事件

(然而在React中,每次進行文字輸入都會出發change事件)。響應通過鍵盤改變焦點的表單元素在得到和失去焦點時會分別出發focus和blur事件

Window事件

Window事件是指事件的發生與瀏覽器視窗本身而非視窗中顯示的任何特定文件內容相關,但是,這些事件中有一些會和文件元素上發生的事件同名.
load事件是這些事件中最重要的一個,當文件和其所有外部資源(比如圖片)完全載入並顯示給使用者時就會觸發它。
unload事件和load相對,當用戶離開當前文件轉向其他文件時會觸發它。
window物件的onerror屬性有點像事件處理程式,當js出錯時會觸發它。
像img元素也可以為load和error事件註冊處理程式

,當外部資源完全載入或載入錯誤的時候就會觸發它們。H5支援abort事件,當圖片或其他網路資源因為使用者停止載入程序而導致失敗就會觸發它
當用戶調整瀏覽器大小或滾動它時會觸發resize和scroll事件。scroll事件也可以在任何可以滾動的元素上觸發,比如那些設定CSS的overflow屬性為scroll的元素

滑鼠事件

對於click事件,detail屬性指定了其是單擊,雙擊或三擊,clientX和clientY屬性指定了滑鼠在視窗座標中的位置
使用者每次移動或拖動滑鼠時,會觸發mousemove事件,這些事件的發生非常頻繁,所以mousemove事件處理程式一定不能觸發計算密集型任務。
在mousedown和mouseup事件佇列之後,瀏覽器也會觸發click事件。懸停和移走會觸發mouseover(不論滑鼠指標穿過被選元素或其子元素,都會觸發 mouseover 事件,只有在滑鼠指標穿過被選元素時,才會觸發 mouseenter 事件)和mouseout事件。
keydown和keyup事件是低階鍵盤事件。當keydown事件產生可列印的字元時,在keydown和keyup之間會觸發另外一個keypress事件

HTML5事件

HTML5的拖放API提供了很多拖放事件,具體可以參考實現H5的拖放 。HTML5定義了歷史管理機制,它允許web應用同瀏覽器的返回和前進按鈕互動(pushState)。HTML5提供瞭解決跨域問題的message事件,也提供了storage事件來監聽資料的本地存取。

觸控式螢幕和移動裝置事件

旋轉移動裝置產生的orientationchange事件,手勢開始時生成gesturestart事件,而手勢結束時生成gestureend事件,在兩個事件之間是跟蹤手勢過程的gesturechange事件。如果想實現自定義手勢,可以監聽touchstart事件和touchmove事件。

註冊事件處理程式

最簡單的方式就是通過on + 事件名稱註冊事件回撥處理函式。這種方法相容性好,缺點是圍繞每個事件目標對於每種事件型別最多隻能有一個事件處理程式(有多個文件時或引用多個依賴時會出現重寫的問題)

addEventListener

addEventListener不影響on繫結的事件處理,同時它能註冊多個處理函式

   function fn1(){
      alert('fn1');
   }
   function fn2(){
      alert('fn2');
   }
   function fn3(){
      alert('fn3');
   }
   var btn = document.getElementById('button');
   btn.onclick = fn1;
   //第三個引數false為事件冒泡,true為事件捕獲
   btn.addEventListener('click', fn2, false);
   btn.addEventListener('click', fn3, false);
   //點選連續彈出3個彈窗(按順序)
   //使用removeEventListener為處理函式解綁
   btn.removeEventListener('click', fn3, false);

IE8及其以下瀏覽器不支援這兩個函式,IE中有類似的函式attachEvent(以這個函式註冊的處理順序可能按照任何順序呼叫),所以需要封裝一個相容函式

事件處理程式的執行環境

在事件處理程式內,this關鍵字指的是事件目標。而使用attachEvent註冊的事件處理函式,this的指向是window,所以要在其中使用call或者apply來改變this指向。

事件處理函式的作用域

事件處理函式的作用域是定義時的作用域(經常通過閉包獲得外部變數)。但是通過HTML屬性註冊事件處理程式是一個例外,他們被轉換成能存取全域性變數的頂級函式而非任何本地變數

事件處理程式的返回值

通常情況下,返回值false是告訴瀏覽器不要執行這個事件相關的預設操作,例如表單提交按鈕的onclick事件處理函式返回false就能組織瀏覽器提交表單。如果使用者輸入不合適的字元,輸入域上的onkeypress事件處理就能通過返回false來過濾鍵盤輸入。返回false的相容性很好。

事件傳播

在呼叫在目標元素上註冊的事件處理函式之後,大部分事件會冒泡到DOM樹根,呼叫目標的父元素的事件處理程式,然後呼叫在目標的祖先元素上註冊的事件處理程式。事件冒泡為大量單獨文件元素上註冊程式提供了更好的方案,即在共同的祖先元素上註冊一個處理程式來處理所有的事件。例如可以在< form>元素上註冊change事件來取代表單上每個元素上的每個元素上註冊change事件處理程式。還有像選項卡中要獲取li的索引,可以通過直接在ul上註冊事件,然後通過事件的target來判斷是哪一個li被點選了
事件冒泡是事件傳播的第三個階段,目標物件本身的事件處理程式呼叫是第二個階段,第一個階段發生在目標處理程式呼叫之前,成為捕獲階段,事件捕獲只能通過addEventListener 註冊,這意味者事件捕獲在IE8之前無法使用。

事件取消

在支援addEventListener 的瀏覽器中,也能通過呼叫事件物件的preventDefault()方法取消事件的預設操作。在IE9之前的IE中,可以通過設定事件物件的returnValue為false來達到相同的效果。下面假設一個事件處理程式,通過能力檢測來判斷瀏覽器支援程度

   function cancelHandler(event){
       //省略其他處理
       //window.event用於IE
       var event = event || window.event;
       if(event.preventDefault) event.preventDefault();
       //IE
       if(event.returnValue) event.returnValue = false;
       return false;       
   }

使用stopPropagation 之後,除了在同一個物件上定義的其他事件處理函式,其他物件上的事件處理程式將不會被呼叫。IE9之前的IE不支援stopPropagation,IE有一個cancelBubble屬性,設定為true可以達到相同效果