JS高階程式設計第十三章.個人學習筆記

賴嘉豪發表於2018-10-29

本文內容:

  • 理解事件流
  • 使用事件處理程式
  • 不同的事件型別


基本概念:javaScript與HTML之間的互動是通過事件實現的。事件,就是文件或瀏覽器視窗中發生的一些特定的互動瞬間。可以使用偵聽器(或處理程式)來預訂事件,以便事件發生時執行相應的程式碼。這種在傳統軟體工程中被稱為觀察員模式的模型,支援頁面的行為(JavaScript)與頁面的外觀(HTML和CSS程式碼)之間的鬆散耦合。


1.事件流


事件流分為兩種:IE的冒泡流 Nercape Communicator的事件捕獲流


1.1 事件冒泡


IE的事件流叫做事件冒泡,即事件開始時有最具體的元素(文件中巢狀層次最深的那個節點)接受,然後逐級向上傳播到較為不具體的節點(文件)。

例如:

<!DOCTYPE html>
<html>
<head>
    <title>Event Bubbling Example</title>
</head>
<body>
    <div id='myDiv'>Click Me</div>
</body>
</html>複製程式碼

如果你單擊了頁面中的<div>元素,那麼這個click事件會按照如下順序傳播:

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

也就是說,click事件首先在<div>元素上發生,而這個元素就是我們單擊的元素。然後,click事件沿DOM樹向上傳播,在每一級節點上都會發生,直至傳播到document物件。


1.2 事件捕獲

Nercape Communicator踢出的另一種事件流叫做事件捕獲。

事件捕獲的思想是不太具體的節點應該更早接收到事件,而最具體的節點應該最後接收到事件。事件捕獲的用意在於事件到達預定目標之前捕獲它。

如果以之前程式碼作為例子,那麼元素就會以下面的順序觸發click事件

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

在事件捕獲的過程中,document物件首先接收到click事件,然後事件沿DOM樹依次向下,一直傳播到事件的實際目標,即<div>元素。

由於老版本的瀏覽器不支援,所以很少使用事件捕獲,所以只有在特殊需要時再使用事件捕獲。


1.3 DOM事件流

“DOM2級事件”規定的事件流包括三個階段:事件捕獲階段、處於目標階段和事件冒泡階段

首先發生的是事件捕獲,為截獲事件提供了機會。

然後是實際的目標接收到事件。

最後一個階段是冒泡階段,可以在這個階段對事件做出響應。


在DOM事件流中,實際的目標(div元素)在捕獲階段不會接收到事件。這意味著在捕獲階段,事件從document到<html>再到<body>後就停止了。下一個階段是“處於目標”階段,於是事件在div上發生,並在事件處理中被看成冒泡階段的一部分。

多數支援DOM事件流的瀏覽器都實現了一種特定的行為;即使'DOM2級事件'規範明確要求捕獲階段不會涉及事件目標,但IE9、Safari、Chrome、Firefox和Opera9.5及更高版本都會在捕獲階段觸發事件物件上的事件。結果就是有兩個機會在目標物件上操作事件。

IE9、Safari、Chrome、Firefox和Opera9.5都支援DOM時間流;IE8及更早版本不支援DOM事件流


2. 事件處理程式

事件就是使用者或瀏覽器自身執行的某種動作。click、load和mouseover,都是事件的名字。而相應某個事件的函式就叫做事件處理程式(或事件偵聽器)。


2.1 HTML事件處理程式

某個元素支援的每種事件,都可以使用一個與相應事件處理程式同名的HTML特性來制定。這個特性的值應該是能夠執行的JavaScript程式碼。

例如,要在按鈕被單擊時執行一些JavaScript,可以像下面這樣編寫程式碼:

<input type='button' value='Click Me' onclick='alert("Clicked")'/>複製程式碼

事件處理程式中的程式碼在執行時,有權訪問全域性作用域中的任何程式碼。

在HTML中定義的事件處理程式可以包含要執行的具體動作,也可以呼叫在頁面其他地方定義的指令碼,如下面的例子所示:

<script type='text/javascript'>
    function showMessage(){
        alert('hello world');
    }
</script>
<input type='button' value='Click Me' onclick='showMessage()' />複製程式碼


在這個例子中,單間牛牛就會呼叫showMessage()函式。這個函式實在一個獨立<script>元素中定義的,當然也可以被包含在一個外部檔案中。這樣指定時間處理程式具有一些獨到之處。首先,這樣會建立一個封裝著元素屬性值的函式。這個函式中有一個區域性變數event,也就是事件物件

<input type='button' value='Click Me' onclick='alert(event.type)' />    // click

複製程式碼

通過event變數,可以直接訪問事件物件,你不用自己定義它,也不用從函式的引數列表中讀取。在這個函式內部,this值等於事件的目標元素,例如:

<input type='button' value='Click Me' onclick='alert(this.value)' /> //Click Me複製程式碼

html中指定事件處理程式有兩個缺點。

首先,存在一個時差問題,如果某個事件處理程式一載入就觸發,而頁面還不具備執行條件的話,就會引發錯誤,因此很多HTML事件處理程式都會被封裝在一個try-catch塊中,以便錯誤不會浮出水面。

另一個缺點是,這樣擴充套件事件處理程式的作用於連在不同瀏覽器中會導致不同結果。不同JavaScript引擎遵循的識別符號解析規則略有差異,很可能會在訪問非限定物件成員時出錯。


因為HTML指定事件處理程式時HTML與JavaScript程式碼緊密耦合,所以一般我們都選擇使用JavaScript指定事件處理程式。


2.2 DOM0級事件處理程式

使用DOM0級方法指定的事件處理程式被認為是元素的方法。因此,這時候的事件處理程式實在元素的作用域中進行;換句話說,程式中的this引用當前元素。

要刪除DOM0級事件處理程式的方法也簡單:

btn.onclick = null複製程式碼


2.3 DOM2級事件處理程式

“DOM2級事件”定義了兩個方法,用於處理指定和刪除事件處理程式的操作:

addEventListener() 和 removeEventListener()。

所有DOM節點中都包含這兩個方法,並且他們都接受3個引數:

要處理的事件名、作為事件處理程式的函式 和 一個布林值

最後一個布林值引數如果是true,表示在捕獲階段呼叫事件處理程式;

如果是false,表示在冒泡階段呼叫事件處理程式

使用DOM2級方法新增事件處理程式的主要好處是可以新增多個事件處理程式

通過addEventListener()新增的事件處理程式只能使用removeEventListener()來移除;移除時傳入的引數與新增處理程式時使用的引數相同。這也意味著通過addEventListener()新增的匿名函式(也就是第二個引數)將無法移除。

不建議在事件捕獲階段註冊事件處理程式


2.4 IE事件處理程式

IE實現了與DOM中類似的兩個方法: attachEvent()和detaEvent()。這兩個方法接受相同的兩個引數:事件處理程式名稱與事件處理程式函式。IE8只支援事件冒泡,所以attachEvent新增的事件都會被新增到冒泡階段。

在IE中使用attachEvent時,this 等於 window。

為同一個元素新增多個事件處理程式時,並非以新增的順序執行,而是以相反的順序執行。

attachEvent新增的事件可以通過detachEvent來移除,道理跟DOM方法一樣。


3.事件物件

在觸發DOM上的某個事件時,會唱生一個事件物件event,這個物件中包含這所有與事件有關的資訊。包括導致事件的元素,事件的型別以及其他與特定事件相關的資訊。例如,滑鼠操作導致的事件物件中,會包含滑鼠位置的資訊,而鍵盤操作導致的事件物件中,會包含與按下的鍵有關的資訊。所有瀏覽器都支援event物件,但支援方式不同。

3.1 DOM中的事件物件

相容DOM的瀏覽器會將一個event物件傳入到事件處理程式中。無論指定時間處理程式時使用說明方法,都會傳入event物件。

event物件包含與建立它特定事件有關的屬性和方法。所有事件都會有下面列出的成員。

屬性/方法(只讀)                           型別                         說明

bubbles                                    Boolean                  表明事件是否冒泡
cancelable                                Boolean                表明事件是否可以取消事件的預設行為
currentTarget                           Element           其事件處理程式當前正在處理事件的那個元素
defaultPrevented                      Boolean                 為true表示已經呼叫了preventDefault()
detail                                         Integer                      與事件相關的細節資訊
eventPhase                                Integer        呼叫事件處理程式的階段:1表示捕獲,2表示                                                                          處於目標,3表示冒泡階段
PreventDefault                       Function                     取消時間的預設行為。如果cancelable是true,則可以使用這個方法
stopImmediatePropagation()  Function       呼叫事件處理程式的階段:1表示捕獲,2表示 處於目標,3表示冒泡階段
 stopPropagation()                 Function        取消時間的進一步捕獲或冒泡。不過bubbles為                                                                         true則可以使用這個方法
target                                     Element          事件的目標
trusted                                    Boolean          為true表示事件是瀏覽器生成的,為false表示                                                                         事件由開發人員通過js建立的
type                                           String            被觸發的事件的型別
view                                        AbstractView     與事件關聯的抽象檢視。等同於發生事件的                                                                               window物件


在事件處理程式內部,獨享this始終等於CurrentTarget的值,而target則只包含事件的實際目標。如果直接將時間處理程式指定給了目標元素,則this、currentTarget和target包含相同的值。

event.target儲存的是觸發事件的元素
event.currentTarget和this儲存的是繫結事件的元素


HTML5事件

hashchange事件

在URL的引數列表發生變化時通知開發人員。

必須要把hashchange事件處理程式新增給window物件,然後URL引數列表只要變化就會呼叫它。此時的event物件應該額外包含兩個屬性:oldURL和newURL。這兩個屬性分別儲存著引數列表變化前後的完整URL。



4.9 觸控與手勢事件

touchstart: 當手指觸控螢幕時觸發;即使已經有一個手指放在了螢幕上也會觸發。
touchmove:當手指在螢幕上滑動時連續地觸發。在這個事件發生期間,呼叫preventDefault()可以阻止滾動。
touchend:當手指從螢幕上移開時觸發
touchcancel:當系統停止跟蹤觸控時觸發。

每個觸控事件的event物件都提供了在滑鼠事件中常見的屬性:bubbles、cancelable、view、clientX、clientY、screenX、screenY、detail、altKey、shiftKey、ctrlKey和metaKey。

除了常見的DOM屬性外,觸控事件還包含下列三個用於跟蹤觸控的屬性。

touches:表示當前跟蹤的觸控操作的Touch物件的陣列。
targetTouchs: 特定於事件目標的Touch物件的陣列。
changeTouches:表示自上次觸控以來發生了什麼改變的Touch物件的陣列。

每個Touch物件包含下列屬性

clientX:觸控目標在視口中的x座標。
clientY:觸控目標在視口中的y座標。
identifier:標識觸控的唯一ID。
pageX:觸控目標在頁面中的x座標。
pageY:觸控目標在頁面中的y座標。
screenX:觸控目標在螢幕中的x座標。
screenY:觸控目標在螢幕中的y座標。
target:觸控的DOM節點目標。


相關文章