概念
事件是您在編程時系統內發生的動作或者發生的事情,系統響應事件後,如果需要,您可以某種方式對事件做出迴應。
在 Web 中, 事件在瀏覽器窗口中被觸發並且通常被綁定到窗口內部的特定部分 — 可能是一個元素、一系列元素、被加載到這個窗口的 HTML 代碼或者是整個瀏覽器窗口。
事件流
事件流描述的是頁面中接受事件的順序。
“DOM2級事件“規定的事件流包括三個階段:事件捕獲階段、處於目標階段和事件冒泡階段。——《JavaScript高級程序設計》
根據W3C模型,事件首先被目標元素所捕獲,然後向上冒泡。——《基於MVC的JavaScript Web富應用開發》
事件捕獲
從頂層的父節點開始觸發事件,從外到內傳播,到觸發事件originTarget結束。
事件冒泡
從內層originTarget節點開始觸發事件,由內向外傳播,逐級冒泡直到頂層節點結束。
注意:不是所有的事件都支持事件冒泡的,blur、focus、load、unload、mouseenter、mouseleave以及自定義事件不支持冒泡。
阻止事件傳播
e.stopPropagation():大家經常聽到的可能是阻止冒泡,實際上這個方法不只能阻止冒泡,還能阻止捕獲階段的傳播。e.stopImmediatePropagation():阻止監聽同一事件的其他事件監聽器被調用。如果多個事件監聽器被附加到相同元素的相同事件類型上,當此事件觸發時,它們會按其被添加的順序被調用。如果在其中一個事件監聽器中執行stopImmediatePropagation(),那麼剩下的事件監聽器都不會被調用。
阻止事件默認行為
e.preventDefault()可以阻止事件的默認行為發生,默認行為是指:點擊a標籤就轉跳到其他頁面、拖拽一個圖片到瀏覽器會自動打開、點擊表單的提交按鈕會提交表單等等,因為有的時候我們並不希望發生這些事情,所以需要阻止默認行為。
注意:
- 只有cancelable屬性為true的事件才可以使用preventDefault()方法來取消其默認行為
- 既要終止冒泡又要阻止默認行為時,直接
return false即可
事件處理器(事件監聽器)
用來響應事件的函數或代碼塊
事件處理程序HTML屬性(內聯事件處理程序)
屬性值就是當事件發生時要運行的JavaScript代碼
<input id="btn" type="button" onclick="handleClick(this.value)" value="hello"/>
<script>
function handleClick(value){
console.log(window.event);
console.log(event);
console.log(event.target);
console.log('this', this); // window
console.log(value); // hello
console.log(this.value); // undefined
}
</script>
通過這種方式指定時,會創建一個封裝着元素屬性值得函數。這個函數中有一個局部變量event(即事件對象)。通過event變量,可以直接訪問事件對象,你不用自己定義它,也不用從函數的參數列表中讀取(經測試,在chrome、和IE11中不用從函數的參數列表讀取,但是在fireFox中則需要)。在這個函數內部,this值等於事件的目標元素。——《JavaScript高級編程》
上面這段話我們可以理解為:通過html屬性指定事件處理程序時,在指定的處理函數外再包裝一層函數,然後將這個新函數賦值給btn.onclick(見DOM0級事件處理程序),這樣新函數作用於內的this就指向了事件目標元素。但是在具體的事件處理函數handler內部,由於沒有 具體的調用對象,在非嚴格模式下它內部的this指向window
DOM0級事件處理程序
var btn = document.getElementById("btn");
btn.onclick = function() {
alert(this.id); // btn
}
DOM2級事件處理程序
主要就是addEventListener和removeEventListener兩個方法,它們都接受3個參數:要處理的事件名、事件處理函數、一個布爾值(表示是否啓用事件捕獲),使用它們的主要好處就是可以添加多個事件處理程序。
注意:如果監聽的函數是匿名函數,沒有任何引用指向它,在不銷燬這個元素的前提下,這個監聽是無法被移除的。
IE事件處理程序(IE7、IE8)
IE實現了attachEvent()和detachEvent()。這兩個方法都接受兩個參數:事件處理程序名稱和事件處理函數。
- 在使用這兩個函數時,事件處理程序會在全局作用域中運行,因此this指向window
- 這些事件處理程序不是以添加它們的方式運行的,而是以相反的順序觸發
跨瀏覽器的事件處理程序
function addHandler(target, eventType, handler) {
if (target.addEventListener) { // DOM2 Events
target.addEventListener(eventType, handler, false);
} else if (target.attachEvent) { // IE
target.attachEvent('on' + eventType, handler);
} else {
target['on' + eventType] = handler;
}
}
function removeHandler(target, eventType, handler) {
if (target.removeEventListener) {
target.removeEventListener(eventType, handler, false);
} else if (target.detachEvent) {
target.detachEvent('on' + eventType, handler);
} else {
target['on' + eventType] = null;
}
}
// 阻止事件 (主要是事件冒泡,因為IE不支持事件捕獲)
function stopPropagation(e) {
if (e.stopPropagation) {
e.stopPropagation(); // 標準w3c
} else {
e.cancelBubble = true; // IE
}
}
// 取消事件的默認行為
function preventDefault(e) {
if (e.preventDefault) {
e.preventDefault(); // 標準w3c
} else {
e.returnValue = false; // IE
}
}
事件委託
通俗來講,就是把一個元素響應事件(click、keydown等)的函數委託到另一個元素。
通常會把一個或一組元素的事件委託到它的父層或者更外層元素上,真正綁定事件的是外層元素,當事件響應到需要綁定的元素上時,會通過事件冒泡機制觸發。
自定義事件
非IE瀏覽器
-
方式一
// 創建事件,參數為事件類型 var event = new Event('Event'); // 初始化事件 // initEvent(type: string, bubbles?: boolean, cancelable?: boolean): void; event.initEvent('build', true, true); elem.addEventListener('build', function(e) { // do something }, false); // 觸發事件 elem.dispatchEvent(event); -
方式二
Event的構造函數定義為new(type: string, eventInitDict?: EventInit): Event;
其中EventInit的定義為:interface EventInit { bubbles?: boolean; // 是否冒泡,默認false cancelable?: boolean; // 是否可取消,默認false composed?: boolean; //是否是否會在shadow DOM根節點之外觸發偵聽器,默認false }// 創建及初始化事件 var event = new Event('build', { bubbles: true, cancelable: true }); elem.addEventListener('build', function(e) { // do something }, false); // 觸發事件 elem.dispatchEvent(event);
IE8及之前瀏覽器
var event = document.createEventObject(); // 不接受任何參數
// 給event的屬性賦值...
elem.fireEvent('onclick', event); // 觸發事件
在調用fireEvent()方法時,會自動為event對象添加srcElement和type屬性;其他屬性則都是必須通過手工添加的。
事件對象
事件對象分為DOM中的事件對象和IE中的事件對象,應該是為了兼容,Event對象的中的屬性和方法將這兩種事件對象的屬性方法都包括進去了。
DOM中事件對象的屬性/方法
bubbles: boolean表明事件是否冒泡cancelable: boolean表明是否可以取消事件默認行為composed: boolean是否是否會在shadow DOM根節點之外觸發偵聽器currentTarget: EventTarget當前正在調用事件處理函數的那個元素defaultPrevented: boolean為true表示已經調用了preventDefault()方法eventPhase: number調用事件處理程序的階段:1表示捕獲階段,2表示“處於目標”,3表示冒泡階段isTrusted: boolean表明是否是瀏覽器生成的事件target: EventTarget事件的目標initEvent(type: string, bubbles?: boolean, cancelable?: boolean): void;preventDefault(): voidstopImmediatePropagation(): voidstopPropagation(): voidtype: string事件類型
IE中的事件對象的屬性/方法
cancelBubble: boolean默認值為false,但將其設置為true就可以取消事件冒泡returnValue: boolean默認值為true,但將其設置為false就可以取消事件的默認行為srcElement: Element事件的目標,對應targettype: string事件類型(IE中的type與DOM中的type是相同的)
注意:target和currentTarget的區別