jQuery入門筆記之(三)事件詳解
在JavaScript 有一個非常重要的功能,就是事件驅動。如果你的網頁需要與用戶進行交互的話,就不可能不用到事件。它在頁面完全加載后,用戶通過鼠標或鍵盤觸發頁面中綁定事件的元素即可觸發。jQuery為開發者更有效率的編寫事件行為,封裝了大量事件方法供我們使用。
基礎事件
一. 綁定事件
如果你學習過原生的javascript事件,比如常用的事件:click、dblclick、mousedown、mouseup、mousemove、mouseover、mouseout等等。如果恰好你使用的是事件綁定的方式進行觸發的話,一定會知道它有多么難處理,各種瀏覽器的兼容性,this的指向等等,但是在jQuery中,一切都不再是問題了。
jQuery 通過.bind()方法來為元素綁定這些事件。可以傳遞三個參數: .bind(eventType [,eventData ],handler(event))
- eventType :表示一個或多個DOM事件類型,比如 click mouseover 。
- eventData :可選參數,表示一個對象,它包含的數據鍵值對映射將被傳遞給事件處理程序。
- handler(event) :表示綁定到指定元素的處理函數。event表示事件對象。
下面就是綁定的幾種方式:
-
點擊按鈕后執行匿名函數
$('button').bind('click', function() { alert('點擊!');//使用點擊事件 });
-
執行普通函數式無須圓括號
$('button').bind('click', fn); function fn() {//普通處理函數 alert('點擊!'); }
-
可以同時綁定多個事件
$('button').bind('mouseout mouseover', function() { $('div').html(function(index, value) { return value + '1';//移入和移出分別執行一次 }); });
-
另一種方式:傳遞一個對象
$('button').bind({ 'mouseout': function() { //事件名的引號可以省略 alert('移出'); }, 'mouseover': function() { alert('移入'); } });
刪除綁定函數:
刪除綁定函數 .unbind( eventType [, handler ] ) 有三種不同的用法:
$('button').unbind(); //刪除當前元素的所有事件,包括匿名執行的,在js中匿名執行的事件函數無法刪除。 $('button').unbind('click'); //刪除當前元素的click事件,使unbind參數刪除指定類型事件 $('button').unbind('click', fn1); //只刪除click事件的fn1處理函數。
二. 簡寫事件
當然jQuery為開發者不簡簡單單提供了事件綁定的方法就不管其它了,為了使開發者更加方便的綁定事件,jQuery 封裝了常用的事件以便節約更多的代碼。我們稱它為簡寫事件。
方法名 | 觸發條件 | 描述 |
---|---|---|
click(fn) | 鼠標 | 觸發每一個匹配元素的 click(單擊)事件 |
dblclick(fn) | 鼠標 | 觸發每一個匹配元素的 dblclick(雙擊)事件 |
mousedown(fn) | 鼠標 | 觸發每一個匹配元素的 mousedown(點擊后)事件 |
mouseup(fn) | 鼠標 | 觸發每一個匹配元素的 mouseup(點擊彈起)事件 |
mouseover(fn) | 鼠標 | 觸發每一個匹配元素的 mouseover(鼠標移入)事件 |
mouseout(fn) | 鼠標 | 觸發每一個匹配元素的 mouseout(鼠標移出)事件 |
mousemove(fn) | 鼠標 | 觸發每一個匹配元素的mousemove(鼠標移動)事件 |
mouseenter(fn) | 鼠標 | 觸發每一個匹配元素的 mouseenter(鼠標穿過)事件 |
mouseleave(fn) | 鼠標 | 觸發每一個匹配元素的 mouseleave(鼠標穿出)事件 |
keydown(fn) | 鍵盤 | 觸發每一個匹配元素的 keydown(鍵盤按下)事件 |
keyup(fn) | 鍵盤 | 觸發每一個匹配元素的 keyup(鍵盤按下彈起)事件 |
keypress(fn) | 鍵盤 | 觸發每一個匹配元素的 keypress(鍵盤按下)事件 |
unload(fn) | 文檔 | 當卸載本頁面時綁定一個要執行的函數 |
resize(fn) | 文檔 | 觸發每一個匹配元素的 resize(文檔改變大小)事件 |
scroll(fn) | 文檔 | 觸發每一個匹配元素的 scroll(滾動條拖動)事件 |
focus(fn) | 表單 | 觸發每一個匹配元素的 focus(焦點激活)事件 |
blur(fn) | 表單 | 觸發每一個匹配元素的 blur(焦點丟失)事件 |
focusin(fn) | 表單 | 觸發每一個匹配元素的 focusin(焦點激活)事件 |
focusout(fn) | 表單 | 觸發每一個匹配元素的 focusout(焦點丟失)事件 |
select(fn) | 表單 | 觸發每一個匹配元素的 select(文本選定)事件 |
change(fn) | 表單 | 觸發每一個匹配元素的 change(值改變)事件 |
submit(fn) | 表單 | 觸發每一個匹配元素的 submit(表單提交)事件 |
大部分事件都如同上面表格中的描述一般比較簡單,也比較好理解。
下面著重講幾個需要注意的地方:
-
unload(fn) 、 resize(fn) 、 scroll(fn) ,使用 $(window) 對象觸發。
-
change(fn) :觸發的條件是,輸入框的值有改變,且失去焦點。
-
submit(fn) :必須在form中,并且使用 $("form") 作為事件觸發元素,不然無效。
-
.mouseover() 和 .mouseout() 表示鼠標移入和移出的時候觸發。那么 jQuery 還封裝了另外一組: .mouseenter() 和 .mouseleave() 表示鼠標穿過和穿出的時候觸發。那么這兩組本質上有什么區別呢?
手冊上的說明是: .mouseenter() 和 .mouseleave() 這組穿過子元素不會觸發,而 .mouseover() 和 .mouseout() 則會觸發。
經過實驗,代碼如下:
<div style="width:100px;height:100px;background:blue;"> <p style="width:100px;height:50px;background:red;"></p> </div> <strong></strong> <script> $('div').mouseover(function () { //移入 div 會觸發,移入 p 再觸發 $('strong').html(function (index, value) { return value+'1'; }); }); </script>
可以看到,鼠標在div內移動時,會不停觸發事件函數,輸出值。而 mouseenter 則不會有這個問題。
- .keydown() 、 .keyup() 返回的是鍵碼,而 .keypress() 返回的是字符編碼。
$('input').keydown(function(e) { alert(e.keyCode); //按下 a 返回 229 }); $('input').keypress(function(e) { alert(e.charCode); //按下 a 返回 97 });
- .focus() 和 .blur() 分別表示光標激活和丟失,事件觸發時機是當前元素。而 .focusin()
和 .focusout() 也表示光標激活和丟失,但是當子元素聚焦或丟失時也觸發事件。
<div style=style="width:100px;height:50px;background:blue;"> <input type="text"> </div> <script> $('div').focusin(function(e) { alert("激活"); //綁定的是 div 元素,子類input觸發 }); $('div').focusout(function(e) { alert("丟失"); }); </script>
三. 復合事件
jQuery 提供了許多最常用的事件效果,組合一些功能實現了一些復合事件,比如切換功能、智能加載等。
方法名 | 描述 |
---|---|
ready(fn) | 當 DOM 加載完畢觸發事件,已經在筆記1中介紹過 |
hover([fn1,]fn2) | 當鼠標移入觸發第一個 fn1,移出觸發 fn2 |
toggle(fn1,fn2[,fn3..]) | 已廢棄,當鼠標點擊觸發 fn1,再點擊觸發 fn2… |
$('div').hover(function () {//背景移入移出切換效果 $(this).css('background', 'black'); //mouseenter 效果 }, function () { $(this).css('background', 'red'); //mouseleave 效果,可省略 });
注意: .hover() 方法是結合了 .mouseenter() 方法和 .mouseleva() 方法,并非 .mouseover()
和 .mouseout() 方法。
.toggle() 有兩層含義,一層就如表格中所說(1.9版移除),一層在動畫中會用到,在這里不進行講述,若想實現表格中的效果也特別簡單,可以進行如下判斷:
var flag = 1; //計數器,標記 $('div').click(function () { if (flag == 1) { //第一次點擊 $(this).css('background', 'black'); flag = 2; } else if (flag == 2) { //第二次點擊 $(this).css('background', 'blue'); flag = 3; } else if (flag == 3) { //第三次點擊 $(this).css('background', 'red'); flag = 1; } });
event對象
JavaScript 在事件處理函數中默認傳遞了 event 對象,也就是事件對象。但由于瀏覽器
的兼容性,開發者總是會做兼容方面的處理。jQuery 在封裝的時候,解決了這些問題,并且
還創建了一些非常好用的屬性和方法。
一. 事件對象
處理函數的e就是event事件對象(JS中需做兼容處理),event 對象有很多可用的屬性和方法,這里先演示一下:
//通過處理函數傳遞事件對象 $('input').bind('click', function (e) { //接受事件對象參數 alert(e.type);//打印出click });
下面是一些常用的屬性:
屬性名 | 描述 |
---|---|
type | 獲取這個事件的事件類型的字符串,例如:click |
target | 獲取綁定事件的 DOM 元素 |
dat | 獲取事件調用時的額外數據 |
relatedTarget | 獲取移入移出目標點離開或進入(最相鄰)的那個 DOM 元素 |
currentTarget | 獲取冒泡前觸發的 DOM 元素,等同與 this |
pageX/pageY | 獲取相對于頁面原點(最左上角)的水平/垂直坐標 |
screenX/screenY | 獲取顯示器屏幕位置的水平/垂直坐標(非 jQuery 封裝) |
clientX/clientY | 獲取相對于頁面視口的水平/垂直坐標(非 jQuery 封裝) |
result | 獲取上一個相同事件的返回值 |
timeStamp | 獲取事件觸發的時間戳 |
whic | 獲取鼠標的左中右鍵(1,2,3),或獲取鍵盤按鍵 |
altKey/shiftKey/ctrlKey | 獲取是否按下了 alt、shift、ctrl(非jQuery 封裝) |
注意:
target :是獲取觸發元素的DOM,就是你點了哪個就是哪個。
currentTarget :是獲取監聽元素的DOM,你把事件綁定在誰身上就是誰。
<div style="width:100px;height:100px;background:#999"> <p style="width:50px;height:50px;background:#333"></p> </div> <script> $('div').bind('click', function (e) { alert(e.target);//點擊p時返回p }); $('div').bind('click', function (e) { alert(e.currentTarget);//無論何時都返回div,等同this }); </script>
通過 event.data 獲取額外數據,可以是數字、字符串、數組、對象
$('input').bind('click', 123, function () { //傳遞 data 數據 alert(e.data); //獲取數字數據123 });
獲取鼠標的左中右鍵
$(document).mousedown(function (e) { alert(e.which); });
獲取鍵盤的按鍵
$('input').keyup(function (e) { alert(e.which); });
//獲取觸發元素鼠標當前的位置
$(document).click(function (e) { alert(e.screenY+ ',' + e.pageY + ',' + e.clientY); });
二. 冒泡和默認行為
如果看我的百度前端技術學院task0002的筆記的話,應該都知道事件冒泡是怎么樣的,事件代理就是根據它來實現的。這里我稍微說一下事件冒泡是什么樣的,事件冒泡其實就是在點擊一個元素時,會一層一層的向父元素遞進當點擊一個div時其實是這樣的 div -> body -> html -> document 。
下面來看一下冒泡和默認行為的一些方法:
方法名 | 描述 |
---|---|
preventDefault() | 阻止某個元素的默認行為 |
isDefaultPrevented() | 判斷是否調用了 preventDefault()方法 |
stopPropagation() | 阻止事件冒泡 |
isPropagationStopped() | 判斷是否調用了 stopPropagation()方法 |
stopImmediatePropagation() | 阻止事件冒泡,并取消該事件的后續事件處理函數 |
isImmediatePropagationStopped() | 判斷是否調用了 stopImmediatePropagation()方法 |
這些方法都是event對象的一些方法,需要注意的是:
先來看到最后兩個,名字都長到讓人記不住的方法,,如代碼中所示:
$("div").click(function(e) { e.stopImmediatePropagation() ; alert("div1");//只彈出div1 }); $("div").click(function(e) { alert("div2");//因第一個點擊事件取消了該事件的后續處理函數,這里將不被執行 });
同時取消默認行為以及事件冒泡:
<a >三省吾身丶丶</a> <script > $("a").click(function(e) { // e.preventDefault();//阻止默認行為 // e.stopPropagation();//阻止事件冒泡 alert("a"); return false; }); $(document).click(function(e) { alert("document"); }); </script>
注意這段代碼中,我們可以看到a被彈出來了,但是鏈接并沒有跳轉,而且document也沒有被彈出,因為 return false 相當于同時了這兩件事情,只不過,在使用表格中的檢測方法時,返回的false。
而使用event對象的方法實現阻止時,檢測返回true。
高級事件
jQuery 不但封裝了大量常用的事件處理,還提供了不少高級事件方便開發者使用。比
如模擬用戶觸發事件、事件委托事件、和統一整合的 on 和 off,以及僅執行一次的 one 方
法。這些方法大大降低了開發者難度,提升了開發者的開發體驗。
一. 模擬操作
在事件觸發的時候,有時我們需要一些模擬用戶行為的操作。例如:當網頁加載完畢后自行點擊一個按鈕觸發一個事件,而不是用戶去點擊。
1. .trigger()
先來一個最機械的 .trigger() :
<button>點擊</button>$("button").click(function() { alert("這里是第一次點擊來自模擬!"); }); $("button").trigger('click');
打開網頁,可以看到內容并不需要被點擊,就直接被彈了出來。
當然不會那么復雜,來進階一下吧,只需要把 .trigger('click') 連在 click 事件之后就可以了,效果當然一樣。
但是,這樣好像還是有點麻煩,jQuery怎么可能讓我們那么麻煩,把添加的字符串刪除,添加 .click() ,現在就是這樣的:
$('input').click(function () { alert('我的第一次點擊來自模擬!');//效果和上面一樣 }).click();
這種簡單的方法jQuery幾乎所有的常用事件都提供了:
blur | focusin | mousedown | resize |
---|---|---|---|
change | focusout | mousenter | scroll |
click | keydown | mouseleave | select |
dblclick | keypress | mousemove | submit |
error | keyup | mouseout | unload |
focus | load | mouseover |
下面來介紹一下 .trigger() 的一些進階用法,當然如果要進行這樣的參數傳遞的話,就不能使用上面的簡單方法了:
有時在模擬用戶行為的時候,我們需要給事件執行傳遞參數,這個參數類似與在事件綁定中的 event.data 的額外數據,可以是數字、字符串、數組、對象。需要注意的是當傳遞一個值的時候,直接傳遞即可。當兩個值以上,需要在前后用中括號包含起來。
$("button").click(function (e, data1, data2) { alert(data1.a + "," + data2[1]);//加載后直接彈出1,456 }).trigger("click", [{"a" : "1", "b" : "2"}, ["123","456"]]);
在使用 bind 時, bind 傳入的額外數據通過 event.data 獲取,該數據傳輸模式不變。
模擬用戶行為時,除了通過 JavaScript 事件名觸發,也可以通過自定義的事件觸發,所謂自定義事件其實就是一個被.bind()綁定的任意函數。
$('input').bind('myEvent', function () { alert('自定義事件!'); }).trigger('myEvent');
2. .triggerHandler()
這是另一個模擬用戶行為的方法,用法和 trigger() 方法一樣。但是在某些情況下有如下區別:
-
.triggerHandler() 方法并不會觸發事件的默認行為,而 .trigger() 會,例如:
$('form').trigger('submit'); //模擬用戶執行提交,并跳轉到執行頁面 $('form').triggerHandler('submit'); //模擬用戶執行提交,并阻止的默認行為
-
.triggerHandler() 方法只會影響第一個匹配到的元素,而 .trigger() 會影響所有。
- .triggerHandler() 方法會返回當前事件執行的返回值,如果沒有返回值,則返回
undefined;而 .trigger() 則返回當前包含事件觸發元素的 jQuery 對象(方便鏈式連綴調用)。 - .trigger() 在創建事件的時候,會冒泡。但這種冒泡是自定義事件才能體現出來,是
jQuery 擴展于 DOM 的機制,并非 DOM 特性。而 .triggerHandler() 不會冒泡。
二. 命名空間
有時,我們想對事件進行移除。但對于同名同元素綁定的事件移除往往比較麻煩,這個時候,可以使用事件的命名空間解決。(主要是處理綁定匿名函數的情況)
$("button").bind('click.abc', function(e) { alert("abc"); }); $("button").bind('click.xyz', function(e) { alert("xyz"); }); $("button").unbind('click.abc' );//處理過后只彈出xyz。
注意:也可以直接使用 ('.abc') ,這樣的話,可以移除 相同命名空間的不同事件 。對于模擬操作 .trigger() 和. triggerHandler() ,用法也是一樣的。 $('input').trigger('click.abc')
三.事件委托
事件委托也就是事件代理。我在 task0002(二)- DOM + 事件 已經談過了。而且也自己實現了一下事件代理,這里稍微再介紹一下:
- “事件代理” 的本質是利用了事件冒泡的特性。當一個元素上的事件被觸發的時候,比如說鼠標點擊了一個按鈕,同樣的事件將會在那個元素的所有祖先元素中被觸發。這一過程被稱為事件冒泡;
- 這個事件從原始元素開始一直冒泡到DOM樹的最上層。任何一個事件的目標元素都是最開始的那個元素,在我們的這個例子中也就是按鈕,并且它在我們的元素對象中以屬性的形式出現。
- 使用事件代理,我們可以把事件處理器添加到一個元素上,等待一個事件從它的子級元素里冒泡上來,并且可以得知這個事件是從哪個元素開始的。
- 對于動態生成的節點同樣有效。
實現如下:
<div> <button>點擊</button> <button>點擊</button> </div> <script> $("div").delegate('button',"click", function() { alert("點擊了");//無論點擊哪個都可以彈出 $("<button>生成</button>").appendTo('div');//點擊同時生成節點,同樣可以點擊彈出 }); //$("div").undelegate('button', 'click');//取消事件代理 </script>
注意: .delegate() 需要指定父元素,然后第一個參數是當前元素,第二個參數是事件方式,第三個參數是執行函數。和 .bind() 方法一樣,可以傳遞額外參數。 .undelegate() 和 .unbind() 方法一樣可以直接刪除所有事件,比如: .undelegate('click') 。也可以刪除命名空間的事件,比如: .undelegate('click.abc') 。
開胃菜完了,下面才是重點!
強大的 on 、 off 和 one
目前綁定事件和解綁的方法有三組共六個。由于這三組的共存可能會造成一定的混亂,為此 jQuery1.7 以后推出了.on()和.off()方法徹底摒棄前面三組。(暫時未移除)
一. on
-
替代 .bind() 方式
$('button').on('click', function () { alert('替代.bind()'); });
-
替代 .bind() 方式,并使用額外數據和事件對象
$('.button').on('click', {user : 'Lee'}, function (e) { alert('替代.bind()' + e.data.user);//lee });
-
替代.bind()方式,并綁定多個事件
$('.button').on('mouseover mouseout', function () { alert('替代.bind()移入移出!'); }); $('.button').on({//以對象模式綁定多個事件 mouseover : function () { alert('替代.bind()移入!'); }, mouseout : function () { alert('替代.bind()移出!'); } });
-
替代.bind()方式,阻止默認行為并取消冒泡
$('form').on('submit', function () { return false; }); $('form').on('submit', false);//在function中只有阻止事件存在時,這樣寫可以簡化代碼,效果相同 $('form').on('submit', function (e) {//當然使用事件對象也是可以的 e.preventDefault();//阻止默認行為 e.stopPropagation();//取消冒泡 });
-
替代 .delegate() ,事件委托
$('div').on('click', 'button', function () { $(this).clone().appendTo('div');//每次點擊都復制一個button });
特別注意: .on() 和 .delegate() 之間的選擇器和事件名稱的位置!因為便于多種事件處理方式,將 選擇器與事件名稱調換了位置
二. off
-
替代 .unbind() 方式,移除事件
$('.button').off('click'); $('.button').off('click', fn); $('.button').off('click.abc');
-
代替 .undelegate() ,取消事件委托
$('#box').off('click', '.button');
注意:和之前方式一樣,事件委托和取消事件委托也有各種搭配方式,比如額外數據、命名空間等等。
三. one
不管是.bind()還是.on(),綁定事件后都不是自動移除事件的,需要通過.unbind()和.off()來手工移除。jQuery 提供了.one()方法,綁定元素執行完畢后自動移除事件,可以方法僅觸發一次的事件。
-
類似于.bind()只觸發一次
$('button').one('click', function () { alert('one 僅觸發一次!'); });
-
類似于.delegate()只觸發一次
$('div').one('click', 'button', function (){ $(this).clone().appendTo('div');//只復制一次 });
所以前面的一系列講述,都是為了拋磚引玉,現在在jQuery中對于事件的處理直接用 on 、 off 和 one 這三個就好了!
來自: http://guowenfh.github.io/2015/12/31/jQuery-03-DetailedEvent/