從零開始學習jQuery (五) 事件與事件對象

本系列文章導航

從零開始學習jQuery (五) 事件與事件對象javascript

 

一.摘要

事件是腳本編程的靈魂. 因此本章內容也是jQuery學習的重點. 本文將對jQuery中的事件處理以及事件對象進行詳細的講解. css

 

二.前言

本篇文章是至今爲止本系列內容最多的一篇, 足以可見其重要性.  你們反映要多列舉示例. 我會在時間容許的狀況下儘可能多列舉示例. 真正的投入生產使用的實例暫時還沒法加入到文章中, 可是可能最後我會列舉一些做品供你們借鑑. 另外本人水平有限, 由於我不是UI設計師. 文章可能有錯誤的地方, 但願你們幫忙指出, 一塊兒學習一塊兒進步. 在技術的世界裏咱們是沒有任何利益瓜葛. 但願你們都抱着彼此鼓勵的心態, 對於回覆中的激進評論我也都會考慮, 可是但願可以彼此尊重, 保護博客園這片程序員的淨土!html

 

三.事件與事件對象

首先看一下咱們常用的添加事件的方式:java

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>javascript中的事件</title> <script type="text/javascript" src="scripts/jquery-1.3.2-vsdoc2.js"></script> <script type="text/javascript"> $(function() { document.getElementById("testDiv2").onclick = showMsg; }) function showMsg(event) { alert("!!!"); } </script> </head> <body> <div id="testDiv1" onclick="showMsg();">單擊事件 1</div> <div id="testDiv2">單擊事件 2</div> </body> </html>


咱們最常使用爲元素添加onclick元素屬性的方式添加事件.node

爲testDiv2的添加onclick事件的方式是修改Dom屬性.jquery

在上一章中已經說明了什麼是元素屬性, 什麼是Dom屬性.這兩種方式的效果相同. 當單擊div時會顯示提示框.程序員

請注意, 雖然效果相同, 可是並不等效.編程

document.getElementById("testDiv2").onclick = showMsg;


等效於:瀏覽器

<div id="testDiv1" onclick="alert("!!!");">單擊事件 1</div>


注意二者的區別了嗎?  咱們經常使用的修改元素屬性添加事件的方式, 其實是創建了一個匿名函數:app

document.getElementById("testDiv1").onclick = function(event) { alert("!!!"); };


這個匿名函數的簽名和咱們手寫的showMsg簽名相同, 因此能夠把showMsg直接賦值給onclick.

這種方式的弊端是:

1. 只能爲一個事件綁定一個事件處理函數.  使用"="賦值會把前面爲此時間綁定的全部事件處理函數沖掉.

2. 在事件函數(不管是匿名函數仍是綁定的函數)中獲取事件對象的方式在不一樣瀏覽器中要特殊處理:

IE中,事件對象是window對象的一個屬性.事件處理函數必須這樣訪問事件對象:

        obj.onclick=function()
        {
            var oEvent = window.event; }

在DOM標準中,事件對象必須做爲惟一參數傳給事件處理函數:

        obj.onclick=function()
        {
            var oEvent = arguments[0]; }

除了使用argument[0]訪問此參數, 咱們也能夠指定參數名稱,上面的代碼等同於:

        obj.onclick=function(oEvent)
        {
            
        }

目前兼容DOM的瀏覽器有Firefox,Safari,Opera,IE7等.

3. 添加多播委託的函數在不一樣瀏覽器中是不同的.

 提供的兼容多瀏覽器添加多播委託的方法:

//統一的爲對象添加多播事件委託的方法
/*  參數說明:  oTarget : 要添加事件的對象.好比"document".  sEventType : 事件類型.好比單擊事件"click".  fnHandler : 發生事件時調用的方法. 好比一個靜態函數"hideCalendar"   使用舉例:  //單擊頁面的任何元素,只要沒有取消冒泡,均可以關閉日曆控件  var cf = document.getElementById("CalFrame");  if( cf != null && hideCalendar != null )  {  ScriptHelper.addEventListener( document, "click", hideCalendar );  } */ scriptHelper.prototype.addEventListener = function(oTarget, sEventType, fnHandler) { if( oTarget.addEventListener )//for dom { oTarget.addEventListener( sEventType, fnHandler, false ) } else if( oTarget.attachEvent )//for ie { oTarget.attachEvent( "on" + sEventType, fnHandler); } }


因此咱們首先應該摒棄<div onclick="..."></div>這種經過修改元素屬性添加事件的方式. 儘可能使用添加多播事件委託的方式爲一個事件綁定多個事件處理函數, 好比爲document對象的單擊事件添加一個關閉彈出層的方法, 使用多播就不會影響document對象原有的事件處理函數.

 

四. jQuery中的事件

有了jQuery,  咱們有了處理對象事件的一系列函數.  上面基礎知識仍是要懂, 可是不再用本身去實現處理多播事件委託的函數了.  正所謂有了jQuery, 每天喝茶水. 下面是在jQuery中最常使用的bind()方法舉例:

$("#testDiv4").bind("click", showMsg);


咱們爲id是testDiv4的元素, 添加列click事件的事件處理函數showMsg.

使用jQuery事件處理函數的好處:

1. 添加的是多播事件委託.  也就是爲click事件又添加了一個方法, 不會覆蓋對象的click事件原有的事件處理函數.

            $("#testDiv4").bind("click", function(event) { alert("one"); }); $("#testDiv4").bind("click", function(event) { alert("two"); });


單擊testDiv4對象時, 依次提示"one"和"two".

2. 統一了事件名稱.  
添加多播事件委託時, ie中是事件名稱前面有"on". 可是使用bind()函數咱們不用區分ie和dom ,  由於內部jQuery已經幫咱們統一了事件的名稱.

3. 能夠將對象行爲所有用腳本控制. 
讓HTML代碼部分只注意"顯示"邏輯. 如今的趨勢是將HTML的行爲, 內容與樣式切分乾淨. 其中用腳本控制元素行爲, 用HTML標籤控制元素內容, 用CSS控制元素樣式. 使用jQuery事件處理函數能夠避免在HTML標籤上直接添加事件.

下面是基礎的jQuery事件處理函數:

事件處理  Event Handling:

名稱 說明 舉例

bind( type, [data], fn )

爲每個匹配元素的特定事件(像click)綁定一個事件處理器函數。 當每一個段落被點擊的時候,彈出其文本: 

$("p").bind("click", function(){ 
  alert( $(this).text() ); 
});

one( type, [data], fn ) 爲每個匹配元素的特定事件(像click)綁定一個一次性的事件處理函數。 當全部段落被第一次點擊的時候,顯示全部其文本: 

$("p").one("click", function(){ 
  alert( $(this).text() ); 
});

trigger( event, [data] ) 在每個匹配的元素上觸發某類事件。 

這個函數也會致使瀏覽器同名的默認行爲的執行。好比,若是用trigger()觸發一個'submit',則一樣會致使瀏覽器提交表單。若是要阻止這種默認行爲,應返回false。

你也能夠觸發由bind()註冊的自定義事件

給一個事件傳遞參數: 

$("p").click( function (event, a, b) { 
  // 一個普通的點擊事件時,a和b是undefined類型 
  // 若是用下面的語句觸發,那麼a指向"foo",而b指向"bar" 
} ).trigger("click", ["foo", "bar"]);

triggerHandler( event, [data] ) 這個特別的方法將會觸發指定的事件類型上全部綁定的處理函數。但不會執行瀏覽器默認動做. 若是你對一個focus事件執行了 .triggerHandler() ,瀏覽器默認動做將不會被觸發,只會觸發你綁定的動做: 

$("#old").click(function(){ 
  $("input").trigger("focus"); 
}); 
$("#new").click(function(){ 
  $("input").triggerHandler("focus"); 
}); 
$("input").focus(function(){   $("<span>Focused!</span>").appendTo("body").fadeOut(1000); });

unbind( type, fn ) bind()的反向操做,從每個匹配的元素中刪除綁定的事件。 

若是沒有參數,則刪除全部綁定的事件。

你能夠將你用bind()註冊的自定義事件取消綁定。

若是提供了事件類型做爲參數,則只刪除該類型的綁定事件。

若是把在綁定時傳遞的處理函數做爲第二個參數,則只有這個特定的事件處理函數會被刪除。

把全部段落的全部事件取消綁定: 
$("p").unbind() 

將段落的click事件取消綁定: 
$("p").unbind( "click" ) 

刪除特定函數的綁定,將函數做爲第二個參數傳入: 

var foo = function () { 
  // 處理某個事件的代碼 
}; 
$("p").bind("click", foo); // ... 當點擊段落的時候會觸發 foo 
$("p").unbind("click", foo); // ... 不再會被觸發 foo

 

五.經常使用事件函數舉例

1.bind( type, [data], fn ) 函數舉例

bind()是最常使用的函數,  注意方法簽名上data參數, 能夠在事件處理以前傳遞一些附加的數據:

function handler(event) { alert(event.data.foo); } $("p").bind("click", {foo: "bar"}, handler) 


注意event參數的使用. jQuery中統一了事件對象, 將事件對象做爲事件處理函數的惟一參數傳遞.

data參數咱們也要經過event.data 進行訪問.  爲什麼要提供data參數呢?

由於咱們常常碰到這樣的問題: 但願在事件處理中根據事件源的某些數據進行特殊處理.

目前網上有兩種存在爭議的解決方法:

(1) 使用自定義元素屬性存儲數據.

好比:

<div id="testDiv5" customer="customer data 1">獲取自定義數據-1</div>

 

在事件處理函數中獲取數據:

$("#testDiv5").bind("click", function(event) { alert($(event.target).attr("customer")); });


attr函數是上一講中的知識, 用於獲取元素的"元素屬性", 並且能夠獲取自定義的元素屬性. 單擊div後將顯示:

image

 

(2) 使用腳本將數據傳遞給事件處理函數:

<div id="testDiv6">獲取自定義數據-2</div>


元素沒有任何的自定義屬性, 添加事件處理函數時將額外的數據傳遞:

$("#testDiv6").bind("click", { customer: "customer data 2" }, function(event) { alert(event.data.customer) });


點擊div後的結果和方法1相同:

image

方法1便於存儲和查找數據. 可是自定義屬性經過不W3C驗證.

方法2必需要本身想辦法存儲數據, 而且要制定規則查找指定元素的數據.

從"開發人員"的角度方法1要更加簡單直觀. 可是缺點比較嚴重. 因此如何取捨請你們本身決定.

one( type, [data], fn ) 函數和bind同樣, 可是隻執行一次.

2. trigger( event, [data] ) 和 triggerHandler( event, [data] )

雖然爲元素綁定了某些事件, 好比click, 可是有時但願在程序中觸發這些事件,  這兩個函數能夠實現此功能.

主要區別是trigger會出發瀏覽器默認的動做, 而triggerHandler不會出發.

經過下面的實例能夠明確的區分這兩個函數:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>jQuery事件處理:trigger和triggerHandler示例</title> <script type="text/javascript" src="scripts/jquery-1.3.2-vsdoc2.js"></script> <script type="text/javascript"> $(function() { $("#old").click(function() { $("#divResult").html(""); $("input").trigger("focus"); }); $("#new").click(function() { $("#divResult").html(""); $("input").triggerHandler("focus"); }); $("input").focus(function() { $("<span>Focused!</span>").appendTo("#divResult"); }); }) </script> </head> <body> <button id="old"> .trigger("focus")</button> <button id="new"> .triggerHandler("focus")</button><br /> <br /> <input type="text" value="To Be Focused" /> <div id="divResult"></div> </body> </html>

 

當單擊".trigger"按鈕時, 會調用兩次Focesed, 而且input元素得到了焦點:

image

單擊".triggerHandler"按鈕時, 只調用一次,而且input元素沒有得到焦點:

image

也就是說, trigger函數出發了瀏覽器默認的獲取焦點的行爲,讓input元素得到了焦點, 因此再次調用了focus事件處理函數.

triggerHandler只調用爲focus事件綁定的事件處理函數, 而不引起瀏覽器行爲, 因此最後input元素沒有得到焦點.

 

 

六.快捷事件 Event Helpers 

BUG提示:jquery-1.3.2-vsdoc2.js 這個最新的官方帶智能提示的類庫, 沒法使用快捷事件, 好比click(), focus(). 使用其餘版本的類庫則沒有問題.

雖然咱們可使用事件處理函數完成對象事件的幾乎全部操做, 可是jQuery提供了對經常使用事件的封裝. 好比單擊事件對應的兩個方法click()和click(fn)分別用來觸發單擊事件和設置單擊事件.

設置單擊事件:

$("#testDiv").click(function(event) { alert("test div clicked ! "); });


等效於:

$("#testDiv").bind("click", function(event) { alert("test div clicked ! "); });

 

觸發單擊事件:

$("#testDiv").click();


等效於

$("#testDiv").trigger("click");

 

注意這裏等效的是trigger而不是triggerHandler.

此類方法在jQuery中英文叫作Event Helpers, 我找不到很好的翻譯方式, 因此按照功能稱其爲"快捷方法",  徵集好的翻譯名稱!

下面是jQuery的快捷方法列表:

因爲都是都是對應的事件, 因此再也不寫說明和舉例了.

名稱 說明 舉例
blur( )    
blur( fn )    
change( )    
change( fn )    
click( )    
click( fn )    
dblclick( )    
dblclick( fn )    
error( )    
error( fn )    
focus( )    
focus( fn )    
keydown( )    
keydown( fn )    
keypress( )    
keypress( fn )    
keyup( )    
keyup( fn )    
load( fn )    
mousedown( fn )    
mouseenter( fn )    
mouseleave( fn )    
mousemove( fn )    
mouseout( fn )    
mouseover( fn )    
mouseup( fn )    
resize( fn )    
scroll( fn )    
select( )    
select( fn )    
submit( )    
submit( fn )    
unload( fn )    

 

七. 交互幫助方法

除了基本的實踐, jQuery提供了兩個和事件相關的幫助方法: hover( over, out ) 和 toggle( fn, fn2, fn3,fn4,... )

1. hover( over, out ) 

hover函數主要解決在原始javascript中mouseover和mouseout函數存在的問題, 看下面這個示例:

image

有兩個div(紅色區域), 裏面分別嵌套了一個div(黃色區域). HTML代碼以下:

    <div class="outer" id="outer1"> Outer 1 <div class="inner" id="inner1">Inner 1</div> </div> <div class="outer" id="outer2"> Outer 2 <div class="inner" id="inner2">Inner 2</div> </div> <div id="console"></div>

 

綁定以下事件:

    <script type="text/javascript"> function report(event) { $('#console').append('<div>'+event.type+'</div>'); } $(function(){ $('#outer1') .bind('mouseover',report) .bind('mouseout',report); $('#outer2').hover(report,report); }); </script>


Outer1咱們使用了mouseover和mouseout事件,  當鼠標從Outer1的紅色區域移動到黃色區域時, 會發現雖然都是在outer1的內部移動, 可是卻觸發了mouseout事件:

image

不少時候咱們不但願出現上圖的結果,  而是但願只有鼠標在Outer1內部移動時不觸發事件, Outer2使用Hover()函數實現了這個效果:

image

注意這裏的事件名稱進入叫作"mouseenter", 離開叫作"mouseleave", 而再也不使用"mouseover"和"mouseleave"事件.

有經驗的開發人員會馬上想到在製做彈出菜單時, 常常遇到這個問題: 爲彈出菜單設置了mouseout事件自動關閉, 可是鼠標在彈出菜單內移動時經常莫名其妙觸發mouseout事件讓菜單關閉. hover()函數幫助咱們很好的解決了這個問題.

2. toggle( fn, fn2, fn3,fn4,... )

toggle函數能夠爲對象添加click事件綁定函數,  可是設置每次點擊後依次的調用函數。

若是點擊了一個匹配的元素,則觸發指定的第一個函數,當再次點擊同一元素時,則觸發指定的第二個函數,若是有更多函數,則再次觸發,直到最後一個。隨後的每次點擊都重複對這幾個函數的輪番調用。

可使用unbind("click")來刪除。

下面的示例演示如何使用toggle函數:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <title>toggle example</title> <link rel="stylesheet" type="text/css" href="css/hover.css"> <script type="text/javascript" src="scripts/jquery-1.3.2-vsdoc2.js"></script> <script type="text/javascript"> $(function() { $("li").toggle( function() { $(this).css({ "list-style-type": "disc", "color": "blue" }); }, function() { $(this).css({ "list-style-type": "square", "color": "red" }); }, function() { $(this).css({ "list-style-type": "none", "color": "" }); } ); }) </script> </head> <body> <ul> <li style="cursor:pointer">click me</li> </ul> </body> </html>


結果是每點擊一次"click me"變換一次列表符號和文字顏色.

 

八.使用jQuery事件對象

使用事件天然少不了事件對象.  由於不一樣瀏覽器之間事件對象的獲取, 以及事件對象的屬性都有差別, 致使咱們很難跨瀏覽器使用事件對象.

jQuery中統一了事件對象,  當綁定事件處理函數時,  會將jQuery格式化後的事件對象做爲惟一參數傳入:

$("#testDiv").bind("click", function(event) { });


關於event對象的詳細說明, 能夠參考jQuery官方文檔: http://docs.jquery.com/Events/jQuery.Event

jQuery事件對象將不一樣瀏覽器的差別進行了合併, 好比能夠在全部瀏覽器中經過 event.target 屬性來獲取事件的觸發者(在IE中使用原生的事件對象, 須要訪問event.srcElement).

下面是jQuery事件對象能夠在擴瀏覽器支持的屬性:

屬性名稱 描述 舉例
type
事件類型.若是使用一個事件處理函數來處理多個事件, 可使用此屬性得到事件類型,好比click.
$("a").click(function(event) {
  alert(event.type);
});
target
獲取事件觸發者DOM對象
$("a[href=http://google.com]").click(function(event) {
  alert(event.target.href);
});
data
事件調用時傳入額外參數.
$("a").each(function(i) {
  $(this).bind('click', {index:i}, function(e){
     alert('my index is ' + e.data.index);
  });
});
relatedTarget
對於鼠標事件, 標示觸發事件時離開或者進入的DOM元素
$("a").mouseout(function(event) {
  alert(event.relatedTarget);
});
currentTarget
冒泡前的當前觸發事件的DOM對象, 等同於this.
$("p").click(function(event) {
  alert( event.currentTarget.nodeName );
});

結果:P
pageX/Y
鼠標事件中, 事件相對於頁面原點的水平/垂直座標.
$("a").click(function(event) {
  alert("Current mouse position: " + event.pageX + ", " + event.pageY );
});
result
上一個事件處理函數返回的值
$("p").click(function(event) {
  return "hey"
});
$("p").click(function(event) {
  alert( event.result );
});

結果:"hey"
timeStamp
事件發生時的時間戳.
var last;
$("p").click(function(event) {
   if( last )
      alert( "time since last event " + event.timeStamp - last );
   last = event.timeStamp;
});

上面是jQuery官方文檔中提供的event對象的屬性. 在"jQuery實戰"一書中還提供了下面的多瀏覽器支持的屬性, 時間關係我沒有嘗試每個屬性, 你們能夠幫忙驗證是否在全部瀏覽器下可用:

屬性名稱 描述 舉例
altKey Alt鍵是否被按下. 按下返回true  
ctrlKey ctrl鍵是否被按下, 按下返回true  
metaKey Meta鍵是否被按下, 按下返回true. 
meta鍵就是PC機器的Ctrl鍵,或者Mac機器上面的Command鍵
 
shiftKey Shift鍵是否被按下, 按下返回true  
keyCode 對於keyup和keydown事件返回被按下的鍵. 不區分大小寫, a和A都返回65. 

對於keypress事件請使用which屬性, 由於which屬性跨瀏覽時依然可靠.
 
which 對於鍵盤事件, 返回觸發事件的鍵的數字編碼. 對於鼠標事件, 返回鼠標按鍵號(1左,2中,3右).  
screenX/Y 對於鼠標事件, 獲取事件相對於屏幕原點的水平/垂直座標  

 

事件對象除了擁有屬性, 還擁有事件. 有一些是必定會用到的事件好比取消冒泡 stopPropagation() 等.下面是jQuery事件對象的函數列表:

名稱 說明 舉例
preventDefault()
取消可能引發任何語意操做的事件. 好比<a>元素的href連接加載, 表單提交以及click引發複選框的狀態切換.
$("a").click(function(event){
  event.preventDefault();
  // do something
});
isDefaultPrevented()
是否調用過
preventDefault()
方法
$("a").click(function(event){
  alert( event.isDefaultPrevented() );
  event.preventDefault();
  alert( event.isDefaultPrevented() );
});
stopPropagation()
取消事件冒泡
$("p").click(function(event){
  event.stopPropagation();
  // do something
});
isPropagationStopped()
是否調用過
stopPropagation()
方法
$("p").click(function(event){
  alert( event.isPropagationStopped() );
  event.stopPropagation();
  alert( event.isPropagationStopped() );
});
stopImmediatePropagation()
取消執行其餘的事件處理函數並取消事件冒泡. 

若是同一個事件綁定了多個事件處理函數, 在其中一個事件處理函數中調用此方法後將不會繼續調用其餘的事件處理函數.
$("p").click(function(event){
  event.stopImmediatePropagation();
});
$("p").click(function(event){
  // This function won't be executed
});
isImmediatePropagationStopped()
是否調用過
stopImmediatePropagation()
方法
$("p").click(function(event){
  alert( event.isImmediatePropagationStopped() );
  event.stopImmediatePropagation();
  alert( event.isImmediatePropagationStopped() );
});


這些函數中  stopPropagation()  是咱們最長用的也是必定會用到的函數. 至關於操做原始event對象的event.cancelBubble=true來取消冒泡.

 

九. 總結

事件是javascript的靈魂, 我花了好久寫這篇文章,翻譯jQuery官方的API文檔. 列表中的不少例子直接從官網上摘抄的,  有些列表中的方法我也沒有用過, 因此若是你們發現問題請及時通知我修改.

接下來的文章將分別講解Ajax和動畫效果.  最後經過講解兩個我修改的jQuery插件來學習jQuery的插件開發.

相關文章
相關標籤/搜索