[js點滴]JavaScript事件Event物件03
Event物件
事件發生以後,會生成一個事件物件,作為引數傳給監聽函式。瀏覽器原生提供一個Event物件,所有的事件都是這個物件的例項,或者說繼承了Event.prototype
物件。
Event物件本身就是一個建構函式,可以用來生成新的例項。
event = new Event(typeArg, eventInit);
Event建構函式接受兩個引數。第一個引數是字串,表示事件的名稱;第二個引數是一個物件,表示事件物件的配置。該引數可以有以下兩個屬性。
-
bubbles:布林值,可選,預設為false,表示事件物件是否冒泡。
-
cancelable:布林值,可選,預設為false,表示事件是否可以被取消。
var ev = new Event("look", {"bubbles":true, "cancelable":false});
document.dispatchEvent(ev);
上面程式碼新建一個look事件例項,然後使用dispatchEvent方法觸發該事件。
IE8及以下版本,事件物件不作為引數傳遞,而是通過window物件的event屬性讀取,並且事件物件的target屬性叫做srcElement屬性。所以,以前獲取事件資訊,往往要寫成下面這樣。
function myEventHandler(event) {
var actualEvent = event || window.event;
var actualTarget = actualEvent.target || actualEvent.srcElement;
// ...
}
上面的程式碼只是為了說明以前的程式為什麼這樣寫,在新程式碼中,這樣的寫法不應該再用了。
以下介紹Event例項的屬性和方法。
bubbles,eventPhase
以下屬性與事件的階段有關。
(1)bubbles
bubbles屬性返回一個布林值,表示當前事件是否會冒泡。該屬性為只讀屬性,只能在新建事件時改變。除非顯式宣告,Event建構函式生成的事件,預設是不冒泡的。
function goInput (e) {
if (!e.bubbles) {
passItOn(e);
} else {
doOutput(e);
}
}
上面程式碼根據事件是否冒泡,呼叫不同的函式。
(2)eventPhase
eventPhase屬性返回一個整數值,表示事件目前所處的節點。
var phase = event.eventPhase;
- 0,事件目前沒有發生。
- 1,事件目前處於捕獲階段,即處於從祖先節點向目標節點的傳播過程中。該過程是從Window物件到Document節點,再到HTMLHtmlElement節點,直到目標節點的父節點為止。
- 2,事件到達目標節點,即target屬性指向的那個節點。
- 3,事件處於冒泡階段,即處於從目標節點向祖先節點的反向傳播過程中。該過程是從父節點一直到Window物件。只有bubbles屬性為true時,這個階段才可能發生。
cancelable,defaultPrevented
以下屬性與事件的預設行為有關。
(1)cancelable
cancelable屬性返回一個布林值,表示事件是否可以取消。該屬性為只讀屬性,只能在新建事件時改變。除非顯式宣告,Event建構函式生成的事件,預設是不可以取消的。
var bool = event.cancelable;
如果要取消某個事件,需要在這個事件上面呼叫preventDefault方法,這會阻止瀏覽器對某種事件部署的預設行為。
(2)defaultPrevented
defaultPrevented屬性返回一個布林值,表示該事件是否呼叫過preventDefault方法。
if (e.defaultPrevented) {
// ...
}
currentTarget,target
以下屬性與事件的目標節點有關。
(1)currentTarget
currentTarget屬性返回事件當前所在的節點,即正在執行的監聽函式所繫結的那個節點。作為比較,target屬性返回事件發生的節點。如果監聽函式在捕獲階段和冒泡階段觸發,那麼這兩個屬性返回的值是不一樣的。
function hide(e){
console.log(this === e.currentTarget); // true
e.currentTarget.style.visibility = "hidden";
}
para.addEventListener('click', hide, false);
上面程式碼中,點選para節點,該節點會不可見。另外,在監聽函式中,currentTarget屬性實際上等同於this物件。
(2)target
target屬性返回觸發事件的那個節點,即事件最初發生的節點。如果監聽函式不在該節點觸發,那麼它與currentTarget屬性返回的值是不一樣的。
function hide(e){
console.log(this === e.target); // 有可能不是true
e.target.style.visibility = "hidden";
}
// HTML程式碼為
// <p id="para">Hello <em>World</em></p>
para.addEventListener('click', hide, false);
上面程式碼中,如果在para節點的em子節點上面點選,則e.target
指向em子節點,導致em子節點(即World部分)會不可見,且輸出false。
在IE6—IE8之中,該屬性的名字不是target,而是srcElement,因此經常可以看到下面這樣的程式碼。
function hide(e) {
var target = e.target || e.srcElement;
target.style.visibility = 'hidden';
}
type,detail,timeStamp,isTrusted
以下屬性與事件物件的其他資訊相關。
(1)type
type
屬性返回一個字串,表示事件型別,大小寫敏感。
var string = event.type;
(2)detail
detail
屬性返回一個數值,表示事件的某種資訊。具體含義與事件型別有關,對於滑鼠事件,表示滑鼠按鍵在某個位置按下的次數,比如對於dblclick事件,detail屬性的值總是2。
function giveDetails(e) {
this.textContent = e.detail;
}
el.onclick = giveDetails;
(3)timeStamp
timeStamp
屬性返回一個毫秒時間戳,表示事件發生的時間。
var number = event.timeStamp;
Chrome在49版以前,這個屬性返回的是一個整數,單位是毫秒(millisecond),表示從Unix紀元開始的時間戳。從49版開始,該屬性返回的是一個高精度時間戳,也就是說,毫秒之後還帶三位小數,精確到微秒。並且,這個值不再從Unix紀元開始計算,而是從PerformanceTiming.navigationStart
開始計算,即表示距離使用者導航至該網頁的時間。如果想將這個值轉為Unix紀元時間戳,就要計算event.timeStamp + performance.timing.navigationStart
。
下面是一個計算滑鼠移動速度的例子,顯示每秒移動的畫素數量。
var previousX;
var previousY;
var previousT;
window.addEventListener('mousemove', function(event) {
if (!(previousX === undefined ||
previousY === undefined ||
previousT === undefined)) {
var deltaX = event.screenX - previousX;
var deltaY = event.screenY - previousY;
var deltaD = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
var deltaT = event.timeStamp - previousT;
console.log(deltaD / deltaT * 1000);
}
previousX = event.screenX;
previousY = event.screenY;
previousT = event.timeStamp;
});
(4)isTrusted
isTrusted
屬性返回一個布林值,表示該事件是否為真實使用者觸發。
var bool = event.isTrusted;
使用者觸發的事件返回true
,指令碼觸發的事件返回false
。
preventDefault()
preventDefault方法取消瀏覽器對當前事件的預設行為,比如點選連結後,瀏覽器跳轉到指定頁面,或者按一下空格鍵,頁面向下滾動一段距離。該方法生效的前提是,事件的cancelable屬性為true,如果為false,則呼叫該方法沒有任何效果。
該方法不會阻止事件的進一步傳播(stopPropagation方法可用於這個目的)。只要在事件的傳播過程中(捕獲階段、目標階段、冒泡階段皆可),使用了preventDefault方法,該事件的預設方法就不會執行。
// HTML程式碼為
// <input type="checkbox" id="my-checkbox" />
var cb = document.getElementById('my-checkbox');
cb.addEventListener(
'click',
function (e){ e.preventDefault(); },
false
);
上面程式碼為點選單選框的事件,設定監聽函式,取消預設行為。由於瀏覽器的預設行為是選中單選框,所以這段程式碼會導致無法選中單選框。
利用這個方法,可以為文字輸入框設定校驗條件。如果使用者的輸入不符合條件,就無法將字元輸入文字框。
function checkName(e) {
if (e.charCode < 97 || e.charCode > 122) {
e.preventDefault();
}
}
上面函式設為文字框的keypress監聽函式後,將只能輸入小寫字母,否則輸入事件的預設事件(寫入文字框)將被取消。
如果監聽函式最後返回布林值false(即return false),瀏覽器也不會觸發預設行為,與preventDefault方法有等同效果。
stopPropagation()
stopPropagation方法阻止事件在DOM中繼續傳播,防止再觸發定義在別的節點上的監聽函式,但是不包括在當前節點上新定義的事件監聽函式。
function stopEvent(e) {
e.stopPropagation();
}
el.addEventListener('click', stopEvent, false);
將上面函式指定為監聽函式,會阻止事件進一步冒泡到el節點的父節點。
stopImmediatePropagation()
stopImmediatePropagation方法阻止同一個事件的其他監聽函式被呼叫。
如果同一個節點對於同一個事件指定了多個監聽函式,這些函式會根據新增的順序依次呼叫。只要其中有一個監聽函式呼叫了stopImmediatePropagation方法,其他的監聽函式就不會再執行了。
function l1(e){
e.stopImmediatePropagation();
}
function l2(e){
console.log('hello world');
}
el.addEventListener('click', l1, false);
el.addEventListener('click', l2, false);
上面程式碼在el節點上,為click事件添加了兩個監聽函式l1和l2。由於l1呼叫了stopImmediatePropagation方法,所以l2不會被呼叫。