jQuery新手入門(五) 事件與事件對象

一.摘要

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

 

二.前言

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

 

三.事件與事件對象

曾經在我的 "Javascript公共腳本庫系列(二): 添加事件多播委託的方法 " 和 "Javascript公共腳本庫系列(三): 格式化事件對象/事件對象詳解 " 兩篇文章中,  曾講解過javascript中的事件和事件對象.

首先看一下我們經常使用的添加事件的方式:

<!
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 > .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }


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

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

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

請注意, 雖然效果相同, 但是並不等效.

document.getElementById("testDiv2"
).onclick = showMsg;
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }


等效於:

<
div
 id
="testDiv1"
 onclick
="alert("
!!!");"
>
單擊事件 1</
div
>
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }


注意兩者的區別了嗎?  我們常用的修改元素屬性添加事件的方式, 實際上是建立了一個匿名函數:

document.getElementById("testDiv1"
).onclick = function
(event
)
{
alert("!!!" );
};
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }


這個匿名函數的簽名和我們手寫的showMsg簽名相同, 所以可以把showMsg直接賦值給onclick.

這種方式的弊端是:

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

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

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

        obj.οnclick=function
()
{
var oEvent = window.event ;
}
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

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

        obj.οnclick=function
()
{
var oEvent = arguments[0];
}
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

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

        obj.οnclick=function
(oEvent)
{

}
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

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

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

下面是在"Javascript公共腳本庫系列(二): 添加事件多播委託的方法 "文章中,  提供的兼容多瀏覽器添加多播委託的方法:

//統一的爲對象添加多播事件委託的方法

/*
參數說明:
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);
}
}
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }


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

 

四. jQuery中的事件

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

$("#testDiv4"
).bind("click"
, showMsg);
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }


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

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

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

            $("#testDiv4"
).bind("click"
, function
(event
) { alert("one"
); });
$("#testDiv4" ).bind("click" , function (event ) { alert("two" ); });
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }


單擊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)
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }


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

data參數我們也要通過event.data 進行訪問.  爲何要提供data參數呢?

因爲我們經常碰到這樣的問題: 希望在事件處理中根據事件源的某些數據進行特殊處理.

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

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

比如:

<
div
 id
="testDiv5"
 customer
="customer data 1"
>
獲取自定義數據-1</
div
>
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

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

$("#testDiv5"
).bind("click"
, function
(event
) { alert($(event
.target).attr("customer"
)); });
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }


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

image

 

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

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


元素沒有任何的自定義屬性, 添加事件處理函數時將額外的數據傳遞: .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

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

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
點擊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 >
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

當單擊".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 ! "
); });

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
等效於:

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

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

觸發單擊事件:

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

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
等效於

$("#testDiv"
).trigger("click"
);
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

 

注意這裏等效的是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 >
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

 

綁定如下事件:

    <
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 >

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
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 >
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }


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

 

八.使用jQuery事件對象

使用事件自然少不了事件對象.  因爲不同瀏覽器之間事件對象的獲取, 以及事件對象的屬性都有差異, 導致我們很難跨瀏覽器使用事件對象.

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

$("#testDiv"
).bind("click"
, function
(event
) {  });
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }


關於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的插件開發.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章