高效使用jquery之一:請使用'On'函式

weixin_34391854發表於2013-12-17

on函式是在jquery 1.7 加入的

描述: 在選定的元素上繫結一個或多個事件處理函式。

定義:
.on( events [, selector ] [, data ], handler(eventObject) )

引數:
events
型別: String
一個或多個空格分隔的事件型別和可選的名稱空間,或僅僅是名稱空間,比如"click", "keydown.myPlugin", 或者 ".myPlugin"。

selector
型別: String
一個選擇器字串,用於過濾出被選中的元素中能觸發事件的後代元素。如果選擇器是 null 或者忽略了該選擇器,那麼被選中的元素總是能觸發事件。

data
型別: Anything
當一個事件被觸發時,要傳遞給事件處理函式的event.data。

handler(eventObject)
型別: Function()
事件被觸發時,執行的函式。若該函式只是要執行return false的話,那麼該引數位置可以直接簡寫成 false。

定義:
.on( events [, selector ] [, data ] )

events
型別: PlainObject
一個物件,鍵是由一個或多個由空格分隔的事件型別及可選的名字空間,值是這些事件型別所對應的事件處理函式。

selector
型別: String
一個選擇器字串,用於過濾出被選中的元素中能觸發事件的後代元素。如果選擇器是 null 或者忽略了該選擇器,那麼被選中的元素總是能觸發事件。

data
型別: Anything
當一個事件被觸發時,要傳遞給事件處理函式的event.data。

.on()方法事件處理程式到當前選定的jQuery物件中的元素。在jQuery 1.7中,.on()方法 提供繫結事件處理的所有功能。為了幫助從舊的jQuery事件方法轉換過來,檢視 .bind(), .delegate(), 和 .live(). 要刪除的.on()繫結的事件,請參閱.off()。要繫結一個事件,並且只執行一次,然後刪除自己, 請參閱.one()

Event names and namespaces(事件名稱和名稱空間)

任何事件的名稱,可以作為events 引數。jQuery將通過所有瀏覽器的標準JavaScript事件型別,當使用者操作事件,如click,瀏覽器會呼叫handler引數的函式。此外,.trigger()方法可以觸發標準的瀏覽器事件 和 自定義事件名繫結的處理程式。

事件名稱可以新增指定的event namespaces(名稱空間) 來簡化刪除或觸發事件。例如,"click.myPlugin.simple"為 click 事件同時定義了兩個名稱空間 myPlugin 和 simple。通過上述方法繫結的 click 事件處理,可以用.off("click.myPlugin") 或 .off("click.simple")刪除繫結到相應元素的Click事件處理程式,而不會干擾其他繫結在該元素上的“click(點選)” 事件。名稱空間類似CSS類,因為它們是不分層次的;只需要有一個名字相匹配即可。以下劃線開頭的名字空間是供 jQuery 使用的。

在.on()方法的第二種用法中,events引數是一個JavaScript物件或者鍵值對。鍵等同於events引數,用空格分隔的事件名稱字串和可選名稱空間。每個鍵的值是一個函式(或false 的值),相當於 handler 引數,但是該值並不是方法中的最後一個引數。在其它方面,這兩種形式在下面描述的內容中其行為都是相同的。如下所述。

Direct and delegated events(直接和委託的事件)

大多數瀏覽器事件冒泡, 或者 傳播,都是由內到外的,從在文件最深處的元素( 事件目標 event target)開始, 一路傳遞到body和document元素。(愚人碼頭注:事件冒泡簡單的說就是,在冒泡路徑上所有繫結了相同事件型別的元素上都會觸發這些型別的事件。)在Internet Explorer 8和更低,一些事件,如change 和 submit本身不泡沫,但 jQuery 為了跨瀏覽器一致性, jQuery 在這些事件上模擬了冒泡行為。

如果省略selector或者是null,那麼事件處理程式被稱為直接事件 或者 直接繫結事件 。每次選中的元素觸發事件時,就會執行處理程式,不管它直接繫結在元素上,還是從後代(內部)元素冒泡到該元素的

當提供selector引數時,事件處理程式是指為委派 事件(愚人碼頭注:通常也有很多人叫它代理事件)。事件不會在直接繫結的元素上觸發,但當selector引數選擇器匹配到後代(內部元素)的時候,事件處理函式才會被觸發。jQuery 會從 event target 開始向上層元素(例如,由最內層元素到最外層元素)開始冒泡,並且在傳播路徑上所有繫結了相同事件的元素若滿足匹配的選擇器,那麼這些元素上的事件也會被觸發。

事件處理只能繫結在當前被選中的元素上;而且,在您的程式碼呼叫.on()的時候,他們必須在頁面文件中已經存在。為了確保目前的元素可以被選擇的(愚人碼頭注:即,存在),最好是在 document 的 ready 事件中進行事件繫結。如果新的HTML被注入頁面時,新的HTML放置到頁面後,事件會繫結到匹配選擇器(selector引數)的元素。或者,使用委派事件繫結事件處理程式,如下所述。

委託事件有一個優勢,他們能在後代元素新增到文件後,可以處理這些事件。 在確保所選擇的元素已經存在的情況下,進行事件繫結時,您可以使用委派的事件,以避免頻繁的繫結事件及解除繫結事件。 例如,這個已經存在的元素可以是 Model-View-Controller(模型 - 檢視 - 控制器)模式中 View(檢視) 的一個容器元素,或document。如果想監視所有文件中的冒泡事件的話。在載入任何其它 HTML 之前,document 元素在 head 中就是有效的,所以您可以安全的在 head 中進行事件繫結,而不需要等待文件載入完。

除了可以給未建立的後代元素繫結事件外(即上面提到的優勢),代理事件的另一個好處就是,當需要監視很多元素的時候,代理事件的開銷更小。例如,在一個表格的 tbody 中含有 1,000 行,下面這個例子會為這 1,000 元素繫結事件:

$("#dataTable tbody tr").on("click", function(event){
alert($(this).text());
});
委派事件的方法只有一個元素的事件處理程式,tbody,並且事件只會向上冒泡一層(從被點選的tr 到 tbody ):

$("#dataTable tbody").on("click", "tr", function(event){
alert($(this).text());
});
注意: 委託事件不能用於SVG.

The event handler and its environment(事件處理程式和它的環境)

handler引數必須是一個函式(或false值,見下文), 除非你傳遞一個物件給events引數。 您可以提供一個匿名處理函式給.on()呼叫,就像上面例子中的用法,或者可以宣告一個函式,然後再將該函式名作為引數:

function notify() { alert("clicked"); }
$("button").on("click", notify);
當瀏覽器觸發一個事件或其他JavaScript呼叫的jQuery的.trigger()方法,jQuery傳遞一個event object給這個處理程式,它可以用來分析和改變事件的狀態。這個物件是由瀏覽器提供一個資料的標註化子集;您需要瀏覽器自己的未經修改的原始 event 物件,您可以使用event.originalEvent得到。例如, event.type 包含事件的名稱(例如, "resize" )和event.target表示事件除非的最深元素(最內層)。

預設情況下,大多數事件的冒泡從最初的 event target(目標元素) 開始的,直到document 元素。每個元素都沿著DOM層級這條路,jQuery會呼叫任何匹配的已被繫結的事件處理程式。一個處理程式可以呼叫的event.stopPropagation()防止事件向上冒泡文件樹( 從而防止這些元素的處理程式執行)。任何繫結到當前元素上的其他處理程式都將執行,為了防止這種情況,可以呼叫event.stopImmediatePropagation()。(繫結在元素上的事件被呼叫的順序和它們被繫結的順序時一樣的。 )

類似地,一個處理程式可以呼叫的event.preventDefault()取消瀏覽器預設操作行為;例如,一個連結上有一個 預設的click事件。並非所有的瀏覽器事件的預設操作,並非所有的預設操作可以被取消。有關詳細資訊,請參閱W3C Events Specification

呼叫event.stopPropagation() 和 event.preventDefault()會從一個事件處理程式會自動返回false。也可以直接將 false 當作 handler 的引數,作為 function(){ return false; } 的簡寫形式。因此,下面的寫法 $("a.disabled").on("click", false); 將會阻止所有含有 "disabled" 樣式的連結的預設行為,並阻止該事件上的冒泡行為。

當jQuery的呼叫處理程式時,this關鍵字指向的是當前正在執行事件的元素。對於直接事件而言,this 代表繫結事件的元素。對於代理事件而言,this 則代表了與 selector 相匹配的元素。(注意,如果事件是從後代元素冒泡上來的話,那麼 this 就有可能不等於 event.target。)若要使用 jQuery 的相關方法,可以根據當前元素建立一個 jQuery 物件,即使用 $(this)。

Passing data to the handler(將資料傳遞到處理程式)

如果data引數給.on()並且不是null 或者 undefined,那麼每次觸發事件時,event.data都傳遞給處理程式。data引數可以是任何型別,但如果是字串型別時,那麼selector引數必須提供,或明確地傳遞null,這樣的 data 引數不會誤認為是選擇器。最好是使用一個物件(鍵值對) ,所以可以作為屬性傳遞多個值。

jQuery的1.4 ,相同的事件處理程式可以多次繫結到一個元素。這對於使用 event.data 功能,或者在閉包中使用唯一的資料時是特別有用的。例如:

function greet(event) { alert("Hello "+event.data.name); }
$("button").on("click", { name: "Karl" }, greet);
$("button").on("click", { name: "Addy" }, greet);
按一下按鈕時,上面的程式碼會產生兩個不同的警報。

除了可以向 .on() 方法傳入 data 引數外,還可以向 .trigger() 或 .triggerHandler() 中傳入該引數。

Event performance(事件效能)

在大多數情況下,一個事件如click很少發生,效能表現並不顯注。但是,高頻率事件比如mousemove 或者 scroll可以每秒觸發幾十個次,在這種情況下明智地使用事件變得更加重要。可以按如下的辦法提高事件的效能:減少事件處理函式中的工作量;對於在事件處理函式中要用到的資訊做好快取而不是再重新計算一次;或使用setTimeout限制的頁面更新的實際次數。

許多委派的事件處理程式繫結到 document 樹的頂層附近,可以降低效能。每次發生事件時,jQuery 需要比較從 event target(目標元素) 開始到文件頂部的路徑中每一個元素上所有該型別的事件。為了獲得更好的效能,在繫結代理事件時,繫結的元素最好儘可能的靠近目標元素。避免在大型文件中,過多的在 document 或 document.body 上新增代理事件。

jQuery可以非常迅速處理tag#id.class形式的簡單選擇器,當它們是用來過濾委派事件。所以"#myForm", "a.external", 和 "button" 都是快速選擇器。若代理事件的選擇器使用了過於複雜的形式,特別是使用了分層選擇器的情況,雖然說這樣做會大大的降低效能,但是對於大多數應用而言,它的速度依然是足夠快的。通過為尋找更合適的元素繫結事件的方法,就可以很簡單的避免使用分層選擇器的情況。例如,使用$("#commentForm").on("click", ".addNew", addComment)而不是$("body").on("click", "#commentForm .addNew", addComment)。

Additional notes(其他注意事項)

有一些事件的速記方法比如.click()可用於附加或觸發事件處理程式。對於速記方法的完整列表, 參見events category

雖然不建議,偽類事件名稱"hover"可以作為"mouseenter mouseleave"的縮寫使用。不要與 接受兩個函式的.hover()方法混淆,這裡只用一個處理函式繫結到偽類事件名稱"hover";處理程式應該檢查的event.type 以確定是否是mouseenter或 mouseleave事件。

jQuery的事件系統需要一個DOM元素可以通過元素的屬性附加資料,使事件就可以被跟蹤和傳遞。object, embed, 和applet元素不能繫結資料,因此不能有jQuery的事件繫結。

W3C指定明確指定focus 和 blur事件沒有冒泡,但是jQuery定義的跨瀏覽器的focusin 和 focusout事件,並且可以冒泡。當focus 和 blur繫結委派的事件處理程式時,jQuery分析名稱,並提供將他們分別交付給focusin 和 focusout。為了保持一致性和清晰度,使用冒泡事件型別的名稱。

在所有的瀏覽器,load ,scroll, 和 error 事件(例如, 在一個 <img> 元素上)不會冒泡。在Internet Explorer 8和更低,paste 和 reset事件不會冒泡,這樣的事件是不支援委派使用,但若事件處理函式是直接繫結在產生事件的元素上的話,是可以使用這些事件的。

window物件上的error 事件使用非標準的引數和返回值約定,所以jQuery 不支援該事件。作為替代,直接用window.onerror屬性分配一個處理函式。

例子:

Example: 當點選段落時,顯示該段落中的文字:
$("p").on("click", function(){
alert( $(this).text() );
});

Example: 向事件處理函式中傳入資料,並且在事件處理函式中通過名字來獲取傳入的資料:
function myHandler(event) {
alert(event.data.foo);
}
$("p").on("click", {foo: "bar"}, myHandler)

Example: 取消表單的提交動作,並且通過返回 false 的方法來防止事件冒泡:
$("form").on("submit", false)

Example: 通過使用 .preventDefault(),僅取消預設的動作。
$("form").on("submit", function(event) {
event.preventDefault();
});

Example: 通過使用 .stopPropagation(),防止提交事件的冒泡行為,但是並不禁止提交行為。
$("form").on("submit", function(event) {
event.stopPropagation();
});

Example: 新增並觸發自定義事件(非瀏覽器事件)。
<!DOCTYPE html>
<html>
<head>
<style>
p { color:red; }
span { color:blue; }
</style>
<script type="text/javascript" src="http://keleyi.com/keleyi/pmedia/jquery/jquery-1.10.2.min.js"></script>
</head>
<body>
<p>Has an attached custom event.</p>
<button>Trigger custom event</button>
<span style="display:none;"></span>
<script>
$("p").on("myCustomEvent", function(e, myName, myValue){
$(this).text(myName + ", hi there!");
$("span").stop().css("opacity", 1)
.text("myName = " + myName)
.fadeIn(30).fadeOut(1000);
});
$("button").click(function () {
$("p").trigger("myCustomEvent", [ "John" ]);
});
</script>

</body>
</html>

例子: 使用 物件 同時新增多個事件處理函式。
<!DOCTYPE html>
<html>
<head>
<style>
.test { color: #000; padding: .5em; border: 1px solid #444; }
.active { color: #900;}
.inside { background-color: aqua; }
</style>
<script src="http://code.jquery.com/jquery-latest.js"></script>
</head>
<body>
<div class="test">test div</div>
<script>$("div.test").on({
click: function(){
$(this).toggleClass("active");
},
mouseenter: function(){
$(this).addClass("inside");
},
mouseleave: function(){
$(this).removeClass("inside");
}
});</script>

</body>
</html>

例子: 點選任何一個段落時,就在它後面追加一個段落。注意,.on() 會為任何段落新增事件,包括新生成的段落,因為當事件冒泡到已經存在的 body 元素上時,就會觸發繫結的事件。
<!DOCTYPE html>
<html>
<head>
<style>
p { background:yellow; font-weight:bold; cursor:pointer;
padding:5px; }
p.over { background: #ccc; }
span { color:red; }
</style>
<script src="http://code.jquery.com/jquery-latest.js"></script>
</head>
<body>
<p>Click me!</p>
<span></span>
<script>
var count = 0;
$("body").on("click", "p", function(){
$(this).after("<p>Another paragraph! "+(++count)+"</p>");
});
</script>

</body>
</html>
Example: 當點選段落時,顯示該段落中的文字:
$("body").on("click", "p", function(){
alert( $(this).text() );
});

Example: 使用 preventDefault 方法,取消連結的預設動作。
$("body").on("click", "a", function(event){
event.preventDefault();
});

相關文章