JavaScript學(xué)習(xí)筆記整理(10):Event事件

2018-06-19 12:01 更新
      客戶端JavaScript程序采用了異步事件驅(qū)動編程模型。

一、相關(guān)術(shù)語

事件就是Web瀏覽器通知應(yīng)用程序發(fā)生了什么事情。

事件類型(event type)是一個用來說明發(fā)生什么類型事件的字符串。例如,“mousemove”表示用戶移動鼠標(biāo),“keydown”表示鍵盤上某個鍵被按下等等。
事件目標(biāo)(event target)是發(fā)生的事件與之相關(guān)的對象。當(dāng)講事件時,我必須同時指明類型和目標(biāo)。比如:window上的load事件或<button>元素的click事件。
在客戶端JavaScript應(yīng)用程序中,Window、Document和Element對象是最常見的事件目標(biāo)。
事件處理程序(event handler)或事件監(jiān)聽程序(event listener)是處理或響應(yīng)事件的函數(shù)。
事件對象(event object)是與特定事件相關(guān)且包含有關(guān)該事件詳細(xì)信息的對象。事件對象作為參數(shù)傳遞給事件處理程序函數(shù)(不包括IE8及之前版本,在這些瀏覽器中有時僅能通過全局變量event才能得到)。所有的事件對象都用來指定事件類型的type屬性和指定事件目標(biāo)的target屬性。(在IE8及之前的版本中用srcElement而非target)
事件傳播(event propagation)是瀏覽器決定哪個對象觸發(fā)其事件處理程序的過程。當(dāng)文檔元素上發(fā)生某個類型的事件時,它們會在文檔樹上向上傳播或“冒泡“(bubble)。
事件傳播的另一種方式:事件捕獲(event capturing):在容器元素上注冊的特定處理程序有機(jī)會在事件傳播到真實目標(biāo)之前捕獲它。

二、Event事件

10.1注冊事件處理程序

注冊事件處理程序有兩種基本方式:
(1)一種是給事件目標(biāo)對象或文檔元素設(shè)置屬性。
按照約定,事件處理程序?qū)傩缘拿钟伞皁n”后面跟著事件名組成:onclick、onchange等。這些屬性名是區(qū)分大小寫的,所有都是小寫,即使是事件類型是由多個詞組成的(比如“readystatechange”)。

<div onclick="alert(1);"></div>


window.onload=function(){}

:盡量少用內(nèi)聯(lián)事件

事件處理程序?qū)傩缘娜秉c是其設(shè)計都是圍繞著假設(shè)每個事件目標(biāo)對于每種事件類型將最多只有一個處理程序。

(2)另一種是通過addEventListener()
window對象、Document對象和所有的文檔元素(Element)都定義了一個名為addEventListener()方法,使用這個方法可以為事件目標(biāo)注冊事件處理程序。

target.addEventListener(type, listener[, useCapture]);

addEventListener方法接受三個參數(shù)。

type:事件名稱(事件類型),字符串,大小寫不敏感。 listener:監(jiān)聽函數(shù)。事件發(fā)生時,會調(diào)用該監(jiān)聽函數(shù)。 useCapture:布爾值,表示監(jiān)聽函數(shù)是否在捕獲階段(capture)觸發(fā),默認(rèn)為false(監(jiān)聽函數(shù)只在冒泡階段被觸發(fā))。老式瀏覽器規(guī)定該參數(shù)必寫,較新版本的瀏覽器允許該參數(shù)可選。為了保持兼容,建議總是寫上該參數(shù)。

使用addEventListener()方法時,事件類型不應(yīng)包括前綴“on”,比如:“onclick”改成“click”等。

addEventListener('click',listener,false);

注意:調(diào)用addEventListener()并不會影響onclick屬性的值。

<button id="mybutton">點擊</button>


var v = document.getElementById('mybutton');

v.onclick = function() {alert('1');}

v.addEventListener('click',function(){alert('2');},false);

上面的代碼中,單擊按鈕會產(chǎn)生兩個alert()對話框。

能通過多次調(diào)用addEventListener()方法為同一個對象注冊同一事件類型的多個處理程序函數(shù)。所有該事件類型的注冊處理程序都會按照注冊的順序調(diào)用。使用相同的參數(shù)在同一個對象上多次調(diào)用addEventListener()是沒用的,處理程序仍然只注冊一次,同時重復(fù)調(diào)用也不會改變調(diào)用處理程序的順序(也就是說,如果為同一個事件多次添加同一個監(jiān)聽函數(shù),函數(shù)只會執(zhí)行一次,多余的添加將自動刪除)。

相對addEventListener()的是 removeEventListener() 方法。
removeEventListener方法的參數(shù),與addEventListener方法完全一致。它的第一個參數(shù)“事件類型”,也是大小寫不敏感。

注意:removeEventListener()方法的事件處理程序函數(shù)必須是函數(shù)名。

dispatchEvent()
dispatchEvent方法在當(dāng)前節(jié)點上觸發(fā)指定事件,從而觸發(fā)監(jiān)聽函數(shù)的執(zhí)行。該方法返回一個布爾值,只要有一個監(jiān)聽函數(shù)調(diào)用了Event.preventDefault(),則返回值為false,否則為true。

target.dispatchEvent(event)

dispatchEvent方法的參數(shù)是一個Event對象的實例。

在IE上
IE9以前的IE不支持addEventListener()和removeEventListener()。不過我們可以使用類似的方法attachEvent()和detachEvent();

attachEvent()detachEvent()方法的工作原理與addEventListener()和removeEventListener()類似,但有所區(qū)別:
  • 因為IE事件模型不支持事件捕獲,所以attachEvent()和detachEvent()只有兩個參數(shù):事件類型和處理程序函數(shù)
  • IE方法的第一個參數(shù)使用了帶“on”前綴的事件處理程序?qū)傩悦?。例如:?dāng)給addEventListener()傳遞“click”時,要給attachEvent()傳遞“onclick”
  • attachEvent()允許相同的事件處理程序函數(shù)注冊多次。當(dāng)特定的事件類型發(fā)生時,注冊函數(shù)的調(diào)用次數(shù)和注冊次數(shù)一樣。

下面的代碼中可以兼容ie瀏覽器:

//添加事件處理器

var addEvent = function(element, type, handler, useCapture) {   

  if(element.addEventListener) {   

    element.addEventListener(type, handler, useCapture ? true : false);   

  } else if(element.attachEvent) {   

    element.attachEvent('on' + type, handler);   

  } else if(element != window){   

    element['on' + type] = handler;   

  }   

};

//移除某個事件處理器

var removeEvent = function(element, type, handler, useCapture) {   

  if(element.removeEventListener) {   

    element.removeEventListener(type, handler, useCapture ? true : false);   } else if(element.detachEvent) {

     element.detachEvent('on' + type, handler);   

  } else if(element != window){   

    element['on' + type] = null;   

  }   

};


10.2 事件處理程序的調(diào)用
一旦注冊了事件處理程序,瀏覽器就會在指定對象上發(fā)生指定類型事件時自動調(diào)用它。

10.2.1 事件處理程序的參數(shù)
通常調(diào)用事件處理程序時把事件對象(event)作為它們的一個參數(shù)。事件對象的屬性提供了有關(guān)事件的詳細(xì)信息。例如,type屬性指定了發(fā)生的事件類型。

在IE8及以前的版本中,通過設(shè)置屬性注冊事件處理程序,當(dāng)調(diào)用它們時并未傳遞事件對象。取而代之,需要通過全局對象window.event來獲得事件對象。
下面的代碼就是考慮了兼容性:

function handler(event){

  event = event || window.event;

}


10.2.2 事件處理程序的運(yùn)行環(huán)境
當(dāng)通過設(shè)置屬性注冊事件處理程序時,看起來就好像是在文檔元素上定義了新方法:

e.onclick=function(){}

事件處理程序在事件目標(biāo)上定義,所以它們作為這個對象的方法來調(diào)用。也就是說,在事件處理程序內(nèi),this關(guān)鍵字指向事件目標(biāo)。

10.2.3 事件處理程序的作用域

事件處理程序在其定義的作用域而非調(diào)用時的作用域中執(zhí)行,并且它們能存取那個作用域中的任何一個本地變量。


10.2.4 事件處理程序的返回值

通過設(shè)置對象屬性或HTML屬性注冊事件處理程序的返回值有時是非常有意義的。通常情況下,返回值false就是告訴瀏覽器不要執(zhí)行這個事件相關(guān)的默認(rèn)操作。比如,表單提交按鈕的onclick事件處理程序能返回false阻止瀏覽器提交表單。

v.onclick = function() {

  return false;

}

理解事件處理程序的返回值只對通過屬性注冊的處理程序才有意義。


10.2.5 調(diào)用順序

文檔元素或其他對象可以指定事件類型注冊多個事件處理程序。當(dāng)適當(dāng)?shù)氖录l(fā)生時,瀏覽器必須按照下面的規(guī)則調(diào)用所有的事件處理程序:

  • 通過設(shè)置對象屬性或HTML屬性注冊的處理程序一直優(yōu)先調(diào)用。
  • 使用addEventListener()注冊的處理程序按照它們的注冊順序調(diào)用。
  • 使用attachEvent()注冊的處理程序可能按照任何順序調(diào)用,所以代碼不應(yīng)該依賴于調(diào)用順序。


10.2.6 事件傳播

當(dāng)事件目標(biāo)是Window對象或其他一些單獨(dú)對象(比如XMLHttpRequest)時,瀏覽器會簡單的通過調(diào)用對象上適當(dāng)?shù)奶幚沓绦蝽憫?yīng)事件。


在調(diào)用在目標(biāo)元素上注冊的事件處理函數(shù)后,大部分事件會“冒泡”到DOM樹根。


 發(fā)生在文檔元素上的大部分事件都會冒泡,但有些例外,比如focus、blur和scroll事件。文檔元素上的load事件會冒泡,但它會在Document對象上停止冒泡而不會傳播到Window對象。只有當(dāng)整個文檔都加載完畢時才會觸發(fā)window對象的load事件。


當(dāng)事件目標(biāo)是文檔或文檔元素時,它會在不同的DOM節(jié)點之間傳播(propagation)。

分為三個階段:

  • 捕獲階段(capture phase):從window對象傳導(dǎo)到目標(biāo)對象。(window--document--....--目標(biāo)對象)
  • 目標(biāo)階段(target phase):目標(biāo)對象本身的事件處理程序調(diào)用。
  • 冒泡階段(bubbling phase):從目標(biāo)對象傳導(dǎo)回window對象。(目標(biāo)對象--父元素--....--document--window)


事件代理(事件委托)

基于事件會在冒泡階段向上傳播到父節(jié)點,我們可以將子節(jié)點的監(jiān)聽事件定義在父節(jié)點上,由父節(jié)點的監(jiān)聽函數(shù)統(tǒng)一處理多個子元素的事件。這種方法叫做事件的代理(delegation)。

<div id="div">   

  <div id="item">123</div>   

</div>


document.getElementById('div').addEventListener('click', function(e) {   

  var target = e.target;   

  if(target.getAttribute('id').toLowerCase() == 'item') {   

    alert(1);   

  }   

});

如果使用事件代理,以后插入的新節(jié)點仍然可以監(jiān)聽的到。


如果使用JQuery,我們要為新增節(jié)點添加事件,除了在新增事件后添加事件外,還可以用下面的代碼:

$(document).on('click','div',function(){})

這種方式其實就是使用了事件代理。


10.2.7 事件取消

用屬性注冊的世界處理程序的返回值能用于取消事件的瀏覽器默認(rèn)操作。在支持addEventListener()的瀏覽器中,也能通過調(diào)用事件對象的preventDefault()方法取消事件的默認(rèn)操作。

在IE9之前的IE中,可以通過設(shè)置事件對象的returnValue屬性為false來達(dá)到同樣的效果。

function cancelHandler(event){

  var event = event || window.event;

  if(event.preventDefault) {event.preventDefault();}  //標(biāo)準(zhǔn)

  if(event.returnValue) { event.returnValue = false;}  // IE

  return false; //用于處理使用對象屬性注冊的處理程序

}


Event對象提供了一個屬性defaultPrevented,返回一個布爾值,默認(rèn)false,表示該事件是否調(diào)用過preventDefault方法。


取消事件傳播

在支持addEventListener()的瀏覽器中,可以調(diào)用事件對象的一個stopPropagation()方法以阻止事件的繼續(xù)傳播。

e.stopPropagation()

//IE

e.cancelBubble = true;


在Event對象上還有一個方法stopImmediatePropagation(),阻止同一個事件的其他監(jiān)聽函數(shù)被調(diào)用。也就是說,如果同一個節(jié)點對于同一個事件指定了多個監(jiān)聽函數(shù),這些函數(shù)會根據(jù)添加的順序依次調(diào)用。只要其中有一個監(jiān)聽函數(shù)調(diào)用了stopImmediatePropagation方法,其他的監(jiān)聽函數(shù)就不會再執(zhí)行了。

e.addEventListener('click',function(event){

  event.stopImmediatePropagation();

});

e.addEventListener('click',function(event){   

  //不會觸發(fā)

});


10.3 文檔事件

(1)beforeunload事件、unload事件、load事件、error事件、pageshow事件、pagehide事件


beforeunload

當(dāng)瀏覽器將要跳轉(zhuǎn)到新頁面時觸發(fā)這個事件。如果事件處理程序返回一個字符串,那么它將出現(xiàn)在詢問用戶是否想離開當(dāng)前頁面的標(biāo)準(zhǔn)對話框中。

window.addEventListener('beforeunload',function(e){

  var message = '你確認(rèn)要離開嗎!';

  e.returnValue = message;

  return message

});


unload

unload事件在窗口關(guān)閉或者document對象將要卸載時觸發(fā),發(fā)生在window、body、frameset等對象上面。它的觸發(fā)順序排在beforeunload、pagehide事件后面。unload事件只在頁面沒有被瀏覽器緩存時才會觸發(fā),換言之,如果通過按下“前進(jìn)/后退”導(dǎo)致頁面卸載,并不會觸發(fā)unload事件。


load、error

load事件直到文檔和所有圖片加載完畢時才會觸發(fā),error事件在頁面加載失敗時觸發(fā)。注意,頁面從瀏覽器緩存加載,并不會觸發(fā)load事件。


pageshow、pagehide

默認(rèn)情況下,瀏覽器會在當(dāng)前會話(session)緩存頁面,當(dāng)用戶點擊“前進(jìn)/后退”按鈕時,瀏覽器就會從緩存中加載頁面。


pageshow事件在頁面加載時觸發(fā),包括第一次加載和從緩存加載兩種情況。如果要指定頁面每次加載(不管是不是從瀏覽器緩存)時都運(yùn)行的代碼,可以放在這個事件的監(jiān)聽函數(shù)。

pageshow事件有一個persisted屬性,返回一個布爾值。頁面第一次加載時,這個屬性是false;當(dāng)頁面從緩存加載時,這個屬性是true。


pagehide事件與pageshow事件類似,當(dāng)用戶通過“前進(jìn)/后退”按鈕,離開當(dāng)前頁面時觸發(fā)。

pagehide事件的event對象有一個persisted屬性,將這個屬性設(shè)為true,就表示頁面要保存在緩存中;設(shè)為false,表示網(wǎng)頁不保存在緩存中,這時如果設(shè)置了unload事件的監(jiān)聽函數(shù),該函數(shù)將在pagehide事件后立即運(yùn)行。


(2)DOMContentLoaded事件、readystatechange事件

DOMContentLoaded事件:當(dāng)文檔加載解析完畢且所有延遲(deferred)腳本(圖片未加載完畢)都執(zhí)行完畢時會觸發(fā),此時圖片和異步(async)腳本可能依舊在加載,但是文檔已經(jīng)為操作準(zhǔn)備就緒了。也就是說,這個事件,發(fā)生在load事件之前。

document.addEventListener('DOMContentLoaded',handler,false);


readystatechange事件:document.readyState屬性會隨著文檔加載過程而變,而每次狀態(tài)改變,Document對象上的readystatechange事件都會觸發(fā)。

document.onreadystatechange = function() {

  if(document.readyState == 'complete'){

    

  }

}


(3)scroll事件、resize事件

scroll事件在文檔或文檔元素滾動時觸發(fā),主要出現(xiàn)在用戶拖動滾動條。

resize事件在改變?yōu)g覽器窗口大小時觸發(fā),發(fā)生在window、body、frameset對象上面。


(4)hashchange事件、popstate事件

hashchange事件在URL的hash部分(即#號后面的部分,包括#號)發(fā)生變化時觸發(fā)。如果老式瀏覽器不支持該屬性,可以通過定期檢查location.hash屬性,模擬該事件。


popstate事件在瀏覽器的history對象的當(dāng)前記錄發(fā)生顯式切換時觸發(fā)。注意,調(diào)用history.pushState()或history.replaceState(),并不會觸發(fā)popstate事件。該事件只在用戶在history記錄之間顯式切換時觸發(fā),比如鼠標(biāo)點擊“后退/前進(jìn)”按鈕,或者在腳本中調(diào)用history.back()、history.forward()、history.go()時觸發(fā)。


(5)cut事件、copy事件、paste事件

這三個事件屬于文本操作觸發(fā)的事件。

cut事件:在將選中的內(nèi)容從文檔中移除,加入剪貼板后觸發(fā)。   

copy事件:在選中的內(nèi)容加入剪貼板后觸發(fā)。   

paste事件:在剪貼板內(nèi)容被粘貼到文檔后觸發(fā)。

這三個事件都有一個clipboardData只讀屬性。該屬性存放剪貼的數(shù)據(jù),是一個DataTransfer對象。


(6)焦點事件

焦點事件發(fā)生在Element節(jié)點和document對象上。

focus事件:Element節(jié)點獲得焦點后觸發(fā),該事件不會冒泡。   

blur事件:Element節(jié)點失去焦點后觸發(fā),該事件不會冒泡。   

focusin事件:Element節(jié)點將要獲得焦點時觸發(fā),發(fā)生在focus事件之前。該事件會冒泡。Firefox不支持該事件。   

focusout事件:Element節(jié)點將要失去焦點時觸發(fā),發(fā)生在blur事件之前。該事件會冒泡。Firefox不支持該事件。

這四個事件的事件對象,帶有target屬性(返回事件的目標(biāo)節(jié)點)和relatedTarget屬性(返回一個Element節(jié)點)。對于focusin事件,relatedTarget屬性表示失去焦點的節(jié)點;對于focusout事件,表示將要接受焦點的節(jié)點;對于focus和blur事件,該屬性返回null。 


由于focus和blur事件不會冒泡,只能在捕獲階段觸發(fā),所以addEventListener方法的第三個參數(shù)需要設(shè)為true。


10.4 鼠標(biāo)事件

(1)click

click事件當(dāng)用戶在Element節(jié)點、document節(jié)點、window對象上,單擊鼠標(biāo)(或者按下回車鍵)時觸發(fā)。


“鼠標(biāo)單擊”定義為,用戶在同一個位置完成一次mousedown動作和mouseup動作。它們的觸發(fā)順序是:mousedown首先觸發(fā),mouseup接著觸發(fā),click最后觸發(fā)。


(2)contextmenu

contextmenu事件在一個節(jié)點上點擊鼠標(biāo)右鍵時觸發(fā),或者按下“上下文菜單”鍵時觸發(fā)。


可以通過下面的方式阻止“上下文菜單”的出現(xiàn):

document.oncontextmenu=function(){        

  return false;    

}


(3)dblclick

dblclick事件當(dāng)用戶在element、document、window對象上,雙擊鼠標(biāo)時觸發(fā)。該事件會在mousedown、mouseup、click之后觸發(fā)。


(4)mousedown、mouseup

mouseup事件在釋放按下的鼠標(biāo)鍵時觸發(fā)。 

mousedown事件在按下鼠標(biāo)鍵時觸發(fā)。


(5)mousemove

mousemove事件當(dāng)鼠標(biāo)在一個節(jié)點內(nèi)部移動時觸發(fā)。當(dāng)鼠標(biāo)持續(xù)移動時,該事件會連續(xù)觸發(fā)。為了避免性能問題,建議對該事件的監(jiān)聽函數(shù)做一些限定,比如限定一段時間內(nèi)只能運(yùn)行一次代碼。


(6)mouseover、mouseenter

mouseover事件和mouseenter事件,都是鼠標(biāo)進(jìn)入一個節(jié)點時觸發(fā)。 


兩者的區(qū)別是,mouseenter事件只觸發(fā)一次,而只要鼠標(biāo)在節(jié)點內(nèi)部移動,mouseover事件會在子節(jié)點上觸發(fā)多次。


(7)mouseout、mouseleave

mouseout事件和mouseleave事件,都是鼠標(biāo)離開一個節(jié)點時觸發(fā)。


除了“mouseenter”和“mouseleave”外的所有鼠標(biāo)事件都能冒泡。鏈接和提交按鈕上的click事件都有默認(rèn)操作且能夠阻止??梢匀∠舷挛牟藛问录碜柚癸@示上下文菜單。


傳遞給鼠標(biāo)事件處理程序的事件對象有clientX和clientY屬性,它們指定了鼠標(biāo)指針相對于包含窗口的坐標(biāo)。加入窗口的滾動偏移量可以把鼠標(biāo)位置轉(zhuǎn)換成文檔坐標(biāo)。


MouseEvent對象的屬性


(1)button、buttons

button屬性指定當(dāng)事件發(fā)生時哪個鼠標(biāo)按鍵按下。

-1:沒有按下鍵。 

0:按下主鍵(通常是左鍵)。 

1:按下輔助鍵(通常是中鍵或者滾輪鍵)。 

2:按下次鍵(通常是右鍵)。

buttons屬性返回一個3個比特位的值,表示同時按下了哪些鍵。它用來處理同時按下多個鼠標(biāo)鍵的情況。

1:二進(jìn)制為001,表示按下左鍵。  

2:二進(jìn)制為010,表示按下右鍵。  

4:二進(jìn)制為100,表示按下中鍵或滾輪鍵。

同時按下多個鍵的時候,每個按下的鍵對應(yīng)的比特位都會有值。比如,同時按下左鍵和右鍵,會返回3(二進(jìn)制為011)。


(2)clientX,clientY 

clientX屬性返回鼠標(biāo)位置相對于瀏覽器窗口左上角的水平坐標(biāo),單位為像素,與頁面是否橫向滾動無關(guān)。 

clientY屬性返回鼠標(biāo)位置相對于瀏覽器窗口左上角的垂直坐標(biāo),單位為像素,與頁面是否縱向滾動無關(guān)。


(3)movementX,movementY 

movementX屬性返回一個水平位移,單位為像素,表示當(dāng)前位置與上一個mousemove事件之間的水平距離。在數(shù)值上,等于currentEvent.movementX = currentEvent.screenX - previousEvent.screenX。 

movementY屬性返回一個垂直位移,單位為像素,表示當(dāng)前位置與上一個mousemove事件之間的垂直距離。在數(shù)值上,等于currentEvent.movementY = currentEvent.screenY - previousEvent.screenY。


(4)screenX,screenY 

screenX屬性返回鼠標(biāo)位置相對于屏幕左上角的水平坐標(biāo),單位為像素。 

screenY屬性返回鼠標(biāo)位置相對于屏幕左上角的垂直坐標(biāo),單位為像素。


(7)pageX、pageY

 pageX和pageY分別是觸點相對HTML文檔左邊沿的X坐標(biāo)和觸點相對HTML文檔上邊沿的Y坐標(biāo)。只讀屬性。

 當(dāng)存在滾動的偏移時,pageX包含了水平滾動的偏移,pageY包含了垂直滾動的偏移。


(6)relatedTarget

relatedTarget屬性返回事件的次要相關(guān)節(jié)點。對于那些沒有次要相關(guān)節(jié)點的事件,該屬性返回null。



10.5 鼠標(biāo)滾輪事件

所有的現(xiàn)代瀏覽器都支持鼠標(biāo)滾輪,并在用戶滾動滾輪時觸發(fā)事件。瀏覽器通常使用鼠標(biāo)滾輪滾動或縮放文檔,但可以通過取消mousewheel事件來阻止這些默認(rèn)操作。


所有瀏覽器都支持“mousewheel”事件,但Firefox使用“DOMMouseScroll”事件。


傳遞給“mousewheel”處理程序的事件對象有wheelDelta屬性,其指定用戶滾動滾輪有多遠(yuǎn)(根據(jù)這個判斷滾動方向)。


遠(yuǎn)離用戶方向的一次鼠標(biāo)滾輪“單擊”的wheelDelta值通常是120,而接近用戶方向的一次“單擊”的值是-120。返回的總是120的倍數(shù)(120表明mouse向上滾動,-120表明鼠標(biāo)向下滾動)


在Safari和Chrome中,為了支持使用二維軌跡球而非一維滾輪的Apple鼠標(biāo),除了wheelDelta屬性外,事件對象還有wheelDeltaX和wheelDeltaY,而wheelDelta和wheelDeltaY的值一直相同。


而在Firefox中,傳遞給“DOMMouseScroll”的屬性是detail。不過, detail屬性值的縮放比率和正負(fù)符號不同wheelDelta,detail值乘以-40和wheelDelta值相等。記錄其滾動距離的是“detail”屬性,它返回的是3的倍數(shù)(3表明mouse向下滾動,-3表明mouse向上滾動)。

window.onmousewheel = document.onmousewheel = scrollWheel;


function scrollWheel(e){

  e = e || window.event;   

  if(e.wheelDelta) { //判斷瀏覽器IE,谷歌滑輪事件                

    if(e.wheelDelta > 0) {   

      //當(dāng)滑輪向上滾動時       

    } else if(e.wheelDelta < 0) { 

      //當(dāng)滑輪向下滾動時        

    };   

  } else if(e.detail) { //Firefox滑輪事件   

    if(e.detail < 0) { 

      //當(dāng)滑輪向上滾動時      

    } else if(e.detail > 0) { 

      //當(dāng)滑輪向下滾動時          

    };   

  };

}


10.6 鍵盤事件

鍵盤事件用來描述鍵盤行為,主要有keydown、keypress、keyup三個事件。  

keydown:按下鍵盤時觸發(fā)該事件。  

keypress:只要按下的鍵并非Ctrl、Alt、Shift和Meta,就接著觸發(fā)keypress事件。 

keyup:松開鍵盤時觸發(fā)該事件。

textinput

任何時候,只要用戶輸入文本都會觸發(fā)。在Webkit瀏覽器中支持“textInput”事件。


事件對象屬性data(保存輸入文本),inputMethod屬性(用于指定輸入源)


注意:keypress和textinput事件是在新輸入的文本真正插入到聚焦的文檔元素前觸發(fā)的。


如果用戶一直按鍵不松開,就會重復(fù)觸發(fā)keydown、keypress,直到用戶松開才會觸發(fā)keyup。


屬性

keycode

指定了輸入字符的編碼。在Firefox中使用的是charCode屬性。


altKey,ctrlKey,metaKey,shiftKey

altKey、ctrlKey、metaKey和shiftKey屬性指定了當(dāng)事件發(fā)生時是否有各種鍵盤輔助鍵按下。

altKey屬性:alt鍵  

ctrlKey屬性:key鍵  

metaKey屬性:Meta鍵(Mac鍵盤是一個四瓣的小花,Windows鍵盤是Windows鍵)  

shiftKey屬性:Shift鍵


key,charCode key屬性返回一個字符串,表示按下的鍵名。如果同時按下一個控制鍵和一個符號鍵,則返回符號鍵的鍵名。比如,按下Ctrl+a,則返回a。如果無法識別鍵名,則返回字符串Unidentified。 


主要功能鍵的鍵名(不同的瀏覽器可能有差異):Backspace,Tab,Enter,Shift,Control,Alt,CapsLock,CapsLock,Esc,Spacebar,PageUp,PageDown,End,Home,Left,Right,Up,Down,PrintScreen,Insert,Del,Win,F(xiàn)1~F12,NumLock,Scroll等。 


charCode屬性返回一個數(shù)值,表示keypress事件按鍵的Unicode值,keydown和keyup事件不提供這個屬性。注意,該屬性已經(jīng)從標(biāo)準(zhǔn)移除,雖然瀏覽器還支持,但應(yīng)該盡量不使用。


String.fromCharCode()

一個keypress事件表示輸入的單個字符。事件對象以數(shù)字Unicode編碼的形式指定字符,所以必須用String.fromChatCode()把它轉(zhuǎn)換成字符串。


10.7 表單事件

(1)input、propertychange

檢測文本輸入元素的value屬性改變,這兩個事件是在新輸入的文本真正插入到聚焦的文檔元素前觸發(fā)的。


一般用在<inupt>和<textarea>里,不過,當(dāng)將contenteditable屬性設(shè)置為true時,只要值變化,也會觸發(fā)這兩個事件。


(2)change

當(dāng)<input>、<select>和<textarea>的值發(fā)生變化時都會觸發(fā)change事件。只有全部修改完成時它才會觸發(fā),這也是它和input事件的區(qū)別。

具體分下面幾種情況:  

激活單選框(radio)或復(fù)選框(checkbox)時觸發(fā)。 

用戶提交時觸發(fā)。比如,從下列列表(select)完成選擇,在日期或文件輸入框完成選擇。 

當(dāng)文本框或textarea元素的值發(fā)生改變,并且喪失焦點時觸發(fā)。


(3)select

當(dāng)<input>和<textarea>中選中文本時觸發(fā)select事件。


(4)reset、submit

這兩個事件是發(fā)生在表單對象上,而不是發(fā)生在表單的成員上。  


reset事件:當(dāng)表單重置(所有表單成員的值變回默認(rèn)值)時觸發(fā)。  

submit事件:當(dāng)表單數(shù)據(jù)向服務(wù)器提交時觸發(fā)。


注意:submit事件的發(fā)生對象是form元素,而不是button元素(即使它的類型是submit),因為提交的是表單,而不是按鈕。


10.8  觸控事件

觸控事件提供了響應(yīng)用戶對觸摸屏或觸摸板上操作的能力。


觸控API提供了下面三個接口

TouchEvent:代表當(dāng)觸摸行為在平面上發(fā)生變化時發(fā)生的事件

Touch:代表用戶與觸摸屏幕間的一個接觸點

TouchList:代表一系列的Touch;一般在用戶多個手指同時解除屏幕時使用


10.8.1 TouchEvent

TouchEvent是一類描述手指在觸摸平面的狀態(tài)變化的事件。


(1)觸摸事件的類型

touchstart:用戶接觸觸摸屏?xí)r觸發(fā),它的target屬性返回發(fā)生觸摸的Element節(jié)點。   


touchend:用戶不再接觸觸摸屏?xí)r(或者移出屏幕邊緣時)觸發(fā),它的target屬性與touchstart事件的target屬性是一致的,它的changedTouches屬性返回一個TouchList對象,包含所有不再觸摸的觸摸點(Touch對象)。   


touchmove:用戶移動觸摸點時觸發(fā),它的target屬性與touchstart事件的target屬性一致。如果觸摸的半徑、角度、力度發(fā)生變化,也會觸發(fā)該事件。   


touchcancel:觸摸點取消時觸發(fā),比如在觸摸區(qū)域跳出一個彈出框窗口(modal window)、觸摸點離開了文檔區(qū)域(進(jìn)入瀏覽器菜單欄區(qū)域)、用戶放置更多的觸摸點(自動取消早先的觸摸點)。


touchenter:當(dāng)觸點進(jìn)去某個elemen時觸發(fā)。沒有冒泡過程。


touchleave:當(dāng)觸點離開某個element時觸發(fā)。沒有冒泡過程。


(2)TouchEvent的屬性

鍵盤屬性

以下屬性都為只讀屬性,返回一個布爾值,表示觸摸的同時,是否按下某個鍵。  

altKey 是否按下alt鍵 

ctrlKey 是否按下ctrl鍵 

metaKey 是否按下meta鍵 

shiftKey 是否按下shift鍵


changedTouches

返回一個TouchList對象,包含了代表所有從上一次觸摸事件到此次事件過程中,狀態(tài)發(fā)生了改變的觸點的Touch對象。只讀屬性。


targetTouches

返回一個TouchList對象,包含了所有當(dāng)前接觸觸摸平面的觸點的Touch對象(也可以說是處于活動狀態(tài)的觸點的Touch對象)。只讀屬性。


touches

返回一個TouchList對象,包含了所有當(dāng)前接觸觸摸平面的觸點的Touch對象。只讀屬性。


type

此次觸摸事件的類型。


target

此次觸摸事件的目標(biāo)元素(element)。這個目標(biāo)元素對應(yīng) TouchEvent.changedTouches 中的觸點的起始元素。


10.8.2 Touch

Touch對象表示在觸控設(shè)備上的觸控點。通常是指手指或觸控筆在觸屏設(shè)備上的操作。


每個Touch對象代表一個觸點,每個觸點由其位置、大小、形狀、壓力大小和目標(biāo)element描述。


(1)Touch屬性

以下屬性描述了用戶的觸摸行為

identifier

此Touch對象的唯一標(biāo)識符。一次觸摸動作在平面上移動的整個過程中,該標(biāo)識符不變,可以根據(jù)它來判斷跟蹤是否在同一次觸摸過程。只讀屬性。


screenX、screenY

screenX和screenY分別是觸點相對屏幕左邊沿的X坐標(biāo)和觸點相對屏幕上邊沿的Y坐標(biāo)。只讀屬性。


clientX、clientY

clientX和clientY分別是觸點相對于可視區(qū)左邊沿的X坐標(biāo)和觸點相對可視區(qū)上邊沿的Y坐標(biāo)。兩個屬性都不包括任何滾動偏移。只讀屬性。


pageX、pageY

pageX和pageY分別是觸點相對HTML文檔左邊沿的X坐標(biāo)和觸點相對HTML文檔上邊沿的Y坐標(biāo)。只讀屬性。

當(dāng)存在滾動的偏移時,pageX包含了水平滾動的偏移,pageY包含了垂直滾動的偏移。


radiusX、radiusY、rotationAngle

radiusX:能夠包圍用戶和觸摸平面的接觸面的最小橢圓的水平軸(X軸)半徑. 這個值的單位和 screenX 相同。只讀屬性。


radiusY:能夠包圍用戶和觸摸平面的接觸面的最小橢圓的垂直軸(Y軸)半徑. 這個值的單位和 screenY 相同。只讀屬性。


rotationAngle:由radiusX 和 radiusY 描述的正方向的橢圓,需要通過順時針旋轉(zhuǎn)這個角度值,才能最精確地覆蓋住用戶和觸摸平面的接觸面,單位為度數(shù),在0到90度之間。只讀屬性。


force

手指擠壓觸摸平面的壓力大小, 從0.0(沒有壓力)到1.0(最大壓力)的浮點數(shù). 只讀屬性.


target

當(dāng)這個觸點最開始被跟蹤時(在 touchstart 事件中), 觸點位于的HTML元素。也就是觸摸發(fā)生時的那個節(jié)點。


10.8.3 TouchList

一個TouchList代表一個觸摸平面上所有觸點的列表。比如一個用戶用三根手指接觸平面,與之相關(guān)的TouchList對于每根手指都會生成一個Touch對象,共計三個。


(1)TouchList的屬性

length

返回TouchList中Touch對象的數(shù)量,只讀屬性。


(2)方法

identifiedTouch()

返回列表中標(biāo)識符與指定值匹配的第一個Touch對象。


item()

返回列表中以指定索引值的Touch對象。也可以使用數(shù)組的語法:touchlist[index]


10.8.4 其他觸控事件

gesturestart、gestureend

scale、rotation


10.9 進(jìn)度事件

進(jìn)度事件用來描述一個事件進(jìn)展的過程。比如XMLHttpRequest對象發(fā)出的HTTP請求的過程、<img>、<audio>、<video>、<style>、<link>加載外部資源的過程。下載和上傳都會發(fā)生進(jìn)度事件。


進(jìn)度事件有以下幾種:

abort事件:當(dāng)進(jìn)度事件被中止時觸發(fā)。如果發(fā)生錯誤,導(dǎo)致進(jìn)程中止,不會觸發(fā)該事件。   

error事件:由于錯誤導(dǎo)致資源無法加載時觸發(fā)。   

load事件:進(jìn)度成功結(jié)束時觸發(fā)。   

loadstart事件:進(jìn)度開始時觸發(fā)。   

loadend事件:進(jìn)度停止時觸發(fā),發(fā)生順序排在error事件\abort事件\load事件后面。   

progress事件:當(dāng)操作處于進(jìn)度之中,由傳輸?shù)臄?shù)據(jù)塊不斷觸發(fā)。   

timeout事件:進(jìn)度超過限時觸發(fā)。


10.11 拖放事件

拖放(Drag-and-Drop,DnD)是在“拖放源(drag source)”和“拖放目標(biāo)(drop target)”之間傳輸數(shù)據(jù)的用戶界面。


拖拉的對象有好幾種,包括Element節(jié)點、圖片、鏈接、選中的文字等等。在HTML網(wǎng)頁中,除了Element節(jié)點默認(rèn)不可以拖拉,其他(圖片、鏈接、選中的文字)都是可以直接拖拉的。為了讓Element節(jié)點可拖拉,可以將該節(jié)點的draggable屬性設(shè)為true。  

<div draggable="true"> 此區(qū)域可拖拉 </div>

 draggable屬性可用于任何Element節(jié)點,但是圖片(img元素)和鏈接(a元素)不加這個屬性,就可以拖拉。對于它們,用到這個屬性的時候,往往是將其設(shè)為false,防止拖拉。


注意:一旦某個Element節(jié)點的draggable屬性設(shè)為true,就無法再用鼠標(biāo)選中該節(jié)點內(nèi)部的文字或子節(jié)點了。


10.11.1 拖放事件:

dragstart:當(dāng)一個元素開始被拖拽的時候觸發(fā)。用戶拖拽的元素需要附加dragstart事件。在這個事件中,監(jiān)聽器將設(shè)置與這次拖拽相關(guān)的信息,例如拖動的數(shù)據(jù)和圖像。


dragenter:當(dāng)拖拽中的鼠標(biāo)第一次進(jìn)入一個元素的時候觸發(fā)。這個事件的監(jiān)聽器需要指明是否允許在這個區(qū)域釋放鼠標(biāo)。如果沒有設(shè)置監(jiān)聽器,或者監(jiān)聽器沒有進(jìn)行操作,則默認(rèn)不允許釋放。當(dāng)你想要通過類似高亮或插入標(biāo)記等方式來告知用戶此處可以釋放,你將需要監(jiān)聽這個事件。


dragover:當(dāng)拖拽中的鼠標(biāo)移動經(jīng)過一個元素的時候觸發(fā)。大多數(shù)時候,監(jiān)聽過程發(fā)生的操作與dragenter事件是一樣的。


dragleave:當(dāng)拖拽中的鼠標(biāo)離開元素時觸發(fā)。監(jiān)聽器需要將作為可釋放反饋的高亮或插入標(biāo)記去除。


drag:這個事件在拖拽源觸發(fā)。即在拖拽操作中觸發(fā)dragstart事件的元素。


drop:這個事件在拖拽操作結(jié)束釋放時于釋放元素上觸發(fā)。一個監(jiān)聽器用來響應(yīng)接收被拖拽的數(shù)據(jù)并插入到釋放之地。這個事件只有在需要時才觸發(fā)。當(dāng)用戶取消了拖拽操作時將不觸發(fā),例如按下了Escape(ESC)按鍵,或鼠標(biāo)在非可釋放目標(biāo)上釋放了按鍵。


dragend:拖拽源在拖拽操作結(jié)束將得到dragend事件對象,不管操作成功與否。

注意點:

  • 拖拉過程只觸發(fā)以上這些拖拉事件,盡管鼠標(biāo)在移動,但是鼠標(biāo)事件不會觸發(fā)。
  • 將文件從操作系統(tǒng)拖拉進(jìn)瀏覽器,不會觸發(fā)dragStart和dragend事件。
  • dragenter和dragover事件的監(jiān)聽函數(shù),用來指定可以放下(drop)拖拉的數(shù)據(jù)。由于網(wǎng)頁的大部分區(qū)域不適合作為drop的目標(biāo)節(jié)點,所以這兩個事件的默認(rèn)設(shè)置為當(dāng)前節(jié)點不允許drop。如果想要在目標(biāo)節(jié)點上drop拖拉的數(shù)據(jù),首先必須阻止這兩個事件的默認(rèn)行為,或者取消這兩個事件。

<div ondragover="return false">  

<div ondragover="event.preventDefault()">

下面是一個例子,將圖片拖放到另一個div中:

<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)"></div>  

<img id="drag1" src="f.jpg" draggable="true" ondragstart="drag(event)" > 


function allowDrop(ev)   

{    

  ev.preventDefault();   

}    

function drag(ev)   

{    

  ev.dataTransfer.setData("Text",ev.target.id);   

}    

function drop(ev)   

{    

  ev.preventDefault();    

  var data=ev.dataTransfer.getData("Text");    

  ev.target.appendChild(document.getElementById(data));   



10.11.2 DataTransfer對象

所有的拖拉事件都有一個dataTransfer屬性,用來保存需要傳遞的數(shù)據(jù)。返回一個DataTransfer對象。


拖拉的數(shù)據(jù)保存兩方面的數(shù)據(jù):數(shù)據(jù)的種類(又稱格式)和數(shù)據(jù)的值。數(shù)據(jù)的種類是一個MIME字符串,比如 text/plain或者image/jpeg,數(shù)據(jù)的值是一個字符串。一般來說,如果拖拉一段文本,則數(shù)據(jù)默認(rèn)就是那段文本;如果拖拉一個鏈接,則數(shù)據(jù)默認(rèn)就是鏈接的URL。 


當(dāng)拖拉事件開始的時候,可以提供數(shù)據(jù)類型和數(shù)據(jù)值;在拖拉過程中,通過dragenter和dragover事件的監(jiān)聽函數(shù),檢查數(shù)據(jù)類型,以確定是否允許放下(drop)被拖拉的對象。比如,在只允許放下鏈接的區(qū)域,檢查拖拉的數(shù)據(jù)類型是否為text/uri-list。 


發(fā)生drop事件時,監(jiān)聽函數(shù)取出拖拉的數(shù)據(jù),對其進(jìn)行處理。


(1)DataTransfer對象的屬性

dropEffect

dropEffect屬性設(shè)置放下(drop)被拖拉節(jié)點時的效果,可能的值包括copy(復(fù)制被拖拉的節(jié)點)、move(移動被拖拉的節(jié)點)、link(創(chuàng)建指向被拖拉的節(jié)點的鏈接)、none(無法放下被拖拉的節(jié)點)。設(shè)置除此以外的值,都是無效的。

e.dataTransfer.dropEffect = 'copy';

dropEffect屬性一般在dragenter和dragover事件的監(jiān)聽函數(shù)中設(shè)置,對于dragstart、drag、dragleave這三個事件,該屬性不起作用。


effectAllowed

effectAllowed屬性設(shè)置本次拖拉中允許的效果,可能的值包括copy(復(fù)制被拖拉的節(jié)點)、move(移動被拖拉的節(jié)點)、link(創(chuàng)建指向被拖拉節(jié)點的鏈接)、copyLink(允許copy或link)、copyMove(允許copy或move)、linkMove(允許link或move)、all(允許所有效果)、none(無法放下被拖拉的節(jié)點)、uninitialized(默認(rèn)值,等同于all)。如果某種效果是不允許的,用戶就無法在目標(biāo)節(jié)點中達(dá)成這種效果。

dragstart事件的監(jiān)聽函數(shù),可以設(shè)置被拖拉節(jié)點允許的效果;dragenter和dragover事件的監(jiān)聽函數(shù),可以設(shè)置目標(biāo)節(jié)點允許的效果。

e.dataTransfer.effectAllowed = 'copy';


files 

files屬性是一個FileList對象,包含一組本地文件,可以用來在拖拉操作中傳送。如果本次拖拉不涉及文件,則屬性為空的FileList對象。


types 

types屬性是一個數(shù)組,保存每一次拖拉的數(shù)據(jù)格式,比如拖拉文件,則格式信息就為File。


(2)DataTransfer對象的方法

setData() 

setData方法用來設(shè)置事件所帶有的指定類型的數(shù)據(jù)。它接受兩個參數(shù),第一個是數(shù)據(jù)類型,第二個是具體數(shù)據(jù)。如果指定的類型在現(xiàn)有數(shù)據(jù)中不存在,則該類型將寫入types屬性;如果已經(jīng)存在,在該類型的現(xiàn)有數(shù)據(jù)將被替換。

e.dataTransfer.setData('text/plain','bb');


getData() 

getData方法接受一個字符串(表示數(shù)據(jù)類型)作為參數(shù),返回事件所帶的指定類型的數(shù)據(jù)(通常是用setData方法添加的數(shù)據(jù))。如果指定類型的數(shù)據(jù)不存在,則返回空字符串。通常只有drop事件觸發(fā)后,才能取出數(shù)據(jù)。如果取出另一個域名存放的數(shù)據(jù),將會報錯。


clearData() 

clearData方法接受一個字符串(表示數(shù)據(jù)類型)作為參數(shù),刪除事件所帶的指定類型的數(shù)據(jù)。如果沒有指定類型,則刪除所有數(shù)據(jù)。如果指定類型不存在,則原數(shù)據(jù)不受影響。

e.dataTransfer.clearData('text/plain');


setDragImage() 

拖動過程中(dragstart事件觸發(fā)后),瀏覽器會顯示一張圖片跟隨鼠標(biāo)一起移動,表示被拖動的節(jié)點。這張圖片是自動創(chuàng)造的,通常顯示為被拖動節(jié)點的外觀,不需要自己動手設(shè)置。setDragImage方法可以用來自定義這張圖片,它接受三個參數(shù),第一個是img圖片元素或者canvas元素,如果省略或為null則使用被拖動的節(jié)點的外觀,第二個和第三個參數(shù)為鼠標(biāo)相對于該圖片左上角的橫坐標(biāo)和右坐標(biāo)。


10.12 自定義事件

我們可以使用自定義事件

//新建事件實例

var event = new Event('play');

//添加監(jiān)聽函數(shù)

element.addEventListener('play',funciton(e){},false);

//觸發(fā)事件

element.dispatchEvent(event);


CustomEvent()

Event構(gòu)造函數(shù)只能指定事件名,不能在事件上綁定數(shù)據(jù)。如果需要在觸發(fā)事件的同時,傳入指定的數(shù)據(jù),需要使用CustomEvent構(gòu)造函數(shù)生成自定義的事件對象。

var event = new CustomEvent('play',{detail: 'play'});

//添加監(jiān)聽函數(shù) element.addEventListener('play',handler,false); //觸發(fā)事件 element.dispatchEvent(event);

CustomEvent構(gòu)造函數(shù)的第一個參數(shù)是事件名稱,第二個參數(shù)是一個對象。在上面的代碼中,該對象的detail屬性會綁定在事件對象之上。

funciton handler(e){

  var data = e.detail;

}


在IE上,并不支持上面的自定義事件寫法,不過,我們可以采用老式寫法:

// 新建Event實例  

var event = document.createEvent('Event');   

// 事件的初始化  

event.initEvent('play', true, true);   

// 加上監(jiān)聽函數(shù)  

document.addEventListener('play', handler, false);   

// 觸發(fā)事件  

document.dispatchEvent(event);

(1)document.createEvent() 

document.createEvent方法用來新建指定類型的事件。它所生成的Event實例,可以傳入dispatchEvent方法。

createEvent方法接受一個字符串作為參數(shù)


(2)event.initEvent() 

事件對象的initEvent方法,用來初始化事件對象,還能向事件對象添加屬性。該方法的參數(shù)必須是一個使用Document.createEvent()生成的Event實例,而且必須在dispatchEvent方法之前調(diào)用。

initEvent方法可以接受四個參數(shù)。

type:事件名稱,格式為字符串。  

bubbles:事件是否應(yīng)該冒泡,格式為布爾值??梢允褂胑vent.bubbles屬性讀取它的值。  

cancelable:事件是否能被取消,格式為布爾值??梢允褂胑vent.cancelable屬性讀取它的值。  

option:為事件對象指定額外的屬性。



學(xué)習(xí)參考資料

書籍:《JavaScript權(quán)威指南》

文檔:MDN--觸摸事件

文章:阮一峰,JavaScript標(biāo)準(zhǔn)參考教程--Event對象





以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號