讀jQuery之十四 (觸發(fā)事件核心方法)
更新時間:2011年08月23日 22:41:43 作者:
觸發(fā)事件,或稱模擬用戶動作。比如點擊,我們可以用代碼去模擬用戶點擊,達到的效果與真實的鼠標點擊是一樣的。
在 事件模塊的演變 我使用了dispatchEvent(標準) 和fireEvent(IE)來主動觸發(fā)事件。如下
...
dispatch = w3c ?
function(el, type){
try{
var evt = document.createEvent('Event');
evt.initEvent(type,true,true);
el.dispatchEvent(evt);
}catch(e){alert(e)};
} :
function(el, type){
try{
el.fireEvent('on'+type);
}catch(e){alert(e)}
};
...
jQuery則完全沒有用到dispatchEvent/fireEvent方法。它采用的是另外一種機制。
jQuery觸發(fā)事件的核心方法是jQuery.event.trigger。它提供給客戶端程序員使用的觸發(fā)事件方法有兩個:.trigger/.triggerHandler

一個事件的發(fā)生在某些元素中可能會導致兩種動作,一個是默認行為,一個是事件handler。如鏈接A
<a onclick="alert(1);">新浪郵箱</a>
點擊后,彈出1(事件handler),點確定跳轉(zhuǎn)(默認行為)到了mail.sina.com.cn。因此,設計的觸發(fā)事件的函數(shù)要考慮到這兩種情況。
jQuery使用.trigger和.triggerHandler區(qū)分了這兩種情況:
.trigger 執(zhí)行事件hanlder/執(zhí)行冒泡/執(zhí)行默認行為
.triggerHandler 執(zhí)行事件handler/不冒泡/不執(zhí)行默認行為
.trigger/.triggerHandler的源碼如下
trigger: function( type, data ) {
return this.each(function() {
jQuery.event.trigger( type, data, this );
});
},
triggerHandler: function( type, data ) {
if ( this[0] ) {
return jQuery.event.trigger( type, data, this[0], true );
}
},
可以看出,兩者都調(diào)用jQuery.event.trigger。調(diào)用時一個沒有傳true,一個傳了。傳了true的triggerHander就表示僅執(zhí)行事件handler。
此外還需注意一點區(qū)別:.trigger是對jQuery對象集合的操作,而.triggerHandler僅操作jQuery對象的第一個元素。如下
<p>p1</p>
<p>p1</p>
<p>p1</p>
<script>
$('p').click(function(){alert(1)});
$('p').trigger('click'); // 彈3次,即三個p的click都觸發(fā)了
$('p').triggerHandler('click'); // 僅彈1次,即只觸發(fā)第一個p的click
</script>
好了,是時候貼出jQuery.event.trigger的代碼了
trigger: function( event, data, elem, onlyHandlers ) {
// Event object or event type
var type = event.type || event,
namespaces = [],
exclusive;
......
}
這就是jQuery.event.trigger的定義,省略了大部分。下面一一列舉
if ( type.indexOf("!") >= 0 ) {
// Exclusive events trigger only for the exact event (no namespaces)
type = type.slice(0, -1);
exclusive = true;
}
這一段是為了處理.trigger('click!')的情形,即觸發(fā)非命名空間的事件。變量exclusive掛在事件對象上后在jQuery.event.handle內(nèi)使用。舉個例子
function fn1() {
console.log(1)
}
function fn2() {
console.log(2)
}
$(document).bind('click.a', fn1);
$(document).bind('click', fn2);
$(document).trigger('click!'); // 2
為document添加了兩個點擊事件,一個是具有命名空間的"click.a",一個則沒有"click"。使用trigger時參數(shù)click后加個嘆號"!"。從輸出結(jié)果為2可以看出不觸發(fā)命名空間的事件??偨Y(jié)一下:
.trigger('click') 觸發(fā)所有的點擊事件
.trigger('click.a') 僅觸發(fā)“click.a” 的點擊事件
.trigger('click!') 觸發(fā)非命名空間的點擊事件
接著看
if ( type.indexOf(".") >= 0 ) {
// Namespaced trigger; create a regexp to match event type in handle()
namespaces = type.split(".");
type = namespaces.shift();
namespaces.sort();
}
這段就很好理解了,就是對.trigger('click.a')的處理,即對具有命名空間事件的處理。
接著看
if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {
// No jQuery handlers for this event type, and it can't have inline handlers
return;
}
對于一些特殊事件如"getData"或?qū)τ谝呀?jīng)觸發(fā)過的事件直接返回。
往下
event = typeof event === "object" ?
// jQuery.Event object
event[ jQuery.expando ] ? event :
// Object literal
new jQuery.Event( type, event ) :
// Just the event type (string)
new jQuery.Event( type );
有三種情況
,event 本身就是jQuery.Event類的實例
,event是個普通js對象(非jQuery.Event類的實例)
,event是個字符串,如"click"
續(xù)
event.type = type;
event.exclusive = exclusive;
event.namespace = namespaces.join(".");
event.namespace_re = new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)");
需要注意exclusive/namespace/namespace_re掛到了event上了,在jQuery.event.handle中可以用到(事件命名空間)。
往下是
// triggerHandler() and global events don't bubble or run the default action
if ( onlyHandlers || !elem ) {
event.preventDefault();
event.stopPropagation();
}
onlyHandlers 只在 .triggerHandler用到了,即不觸發(fā)元素的默認行為,且停止冒泡。
下面是
// Handle a global trigger
if ( !elem ) {
// TODO: Stop taunting the data cache; remove global events and always attach to document
jQuery.each( jQuery.cache, function() {
// internalKey variable is just used to make it easier to find
// and potentially change this stuff later; currently it just
// points to jQuery.expando
var internalKey = jQuery.expando,
internalCache = this[ internalKey ];
if ( internalCache && internalCache.events && internalCache.events[ type ] ) {
jQuery.event.trigger( event, data, internalCache.handle.elem );
}
});
return;
}
這里是個遞歸調(diào)用。如果沒有傳elem元素,那么從jQuery.cache里取。
接著是
// Don't do events on text and comment nodes
if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
return;
}
屬性,文本節(jié)點直接返回。
下面是
// Clone any incoming data and prepend the event, creating the handler arg list
data = data != null ? jQuery.makeArray( data ) : [];
data.unshift( event );
先將參數(shù)data放入數(shù)組,event對象放在數(shù)組的第一個位置。
接著是
// Fire event on the current element, then bubble up the DOM tree
do {
var handle = jQuery._data( cur, "handle" );
event.currentTarget = cur;
if ( handle ) {
handle.apply( cur, data );
}
// Trigger an inline bound script
if ( ontype && jQuery.acceptData( cur ) && cur[ ontype ] && cur[ ontype ].apply( cur, data ) === false ) {
event.result = false;
event.preventDefault();
}
// Bubble up to document, then to window
cur = cur.parentNode || cur.ownerDocument || cur === event.target.ownerDocument && window;
} while ( cur && !event.isPropagationStopped() );
這段代碼很重要,做了以下事情
,取handle
,執(zhí)行
,執(zhí)行通過onXXX方式添加的事件(如onclick="fun()")
,取父元素
while循環(huán)不斷重復這四步以模擬事件冒泡。直到window對象。
接下是
// If nobody prevented the default action, do it now
if ( !event.isDefaultPrevented() ) {
var old,
special = jQuery.event.special[ type ] || {};
if ( (!special._default || special._default.call( elem.ownerDocument, event ) === false) &&
!(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
// Call a native DOM method on the target with the same name name as the event.
// Can't use an .isFunction)() check here because IE6/7 fails that test.
// IE<9 dies on focus to hidden element (#1486), may want to revisit a try/catch.
try {
if ( ontype && elem[ type ] ) {
// Don't re-trigger an onFOO event when we call its FOO() method
old = elem[ ontype ];
if ( old ) {
elem[ ontype ] = null;
}
jQuery.event.triggered = type;
elem[ type ]();
}
} catch ( ieError ) {}
if ( old ) {
elem[ ontype ] = old;
}
jQuery.event.triggered = undefined;
}
}
這一段是對于瀏覽器默認行為的觸發(fā)。如form.submit(),button.click()等。
注意,由于Firefox中鏈接的安全性限制,jQuery對鏈接的默認行為都統(tǒng)一為不能觸發(fā)。即不能通過.trigger()使鏈接跳轉(zhuǎn)。
復制代碼 代碼如下:
...
dispatch = w3c ?
function(el, type){
try{
var evt = document.createEvent('Event');
evt.initEvent(type,true,true);
el.dispatchEvent(evt);
}catch(e){alert(e)};
} :
function(el, type){
try{
el.fireEvent('on'+type);
}catch(e){alert(e)}
};
...
jQuery則完全沒有用到dispatchEvent/fireEvent方法。它采用的是另外一種機制。
jQuery觸發(fā)事件的核心方法是jQuery.event.trigger。它提供給客戶端程序員使用的觸發(fā)事件方法有兩個:.trigger/.triggerHandler

一個事件的發(fā)生在某些元素中可能會導致兩種動作,一個是默認行為,一個是事件handler。如鏈接A
<a onclick="alert(1);">新浪郵箱</a>
點擊后,彈出1(事件handler),點確定跳轉(zhuǎn)(默認行為)到了mail.sina.com.cn。因此,設計的觸發(fā)事件的函數(shù)要考慮到這兩種情況。
jQuery使用.trigger和.triggerHandler區(qū)分了這兩種情況:
.trigger 執(zhí)行事件hanlder/執(zhí)行冒泡/執(zhí)行默認行為
.triggerHandler 執(zhí)行事件handler/不冒泡/不執(zhí)行默認行為
復制代碼 代碼如下:
.trigger/.triggerHandler的源碼如下
trigger: function( type, data ) {
return this.each(function() {
jQuery.event.trigger( type, data, this );
});
},
triggerHandler: function( type, data ) {
if ( this[0] ) {
return jQuery.event.trigger( type, data, this[0], true );
}
},
可以看出,兩者都調(diào)用jQuery.event.trigger。調(diào)用時一個沒有傳true,一個傳了。傳了true的triggerHander就表示僅執(zhí)行事件handler。
此外還需注意一點區(qū)別:.trigger是對jQuery對象集合的操作,而.triggerHandler僅操作jQuery對象的第一個元素。如下
復制代碼 代碼如下:
<p>p1</p>
<p>p1</p>
<p>p1</p>
<script>
$('p').click(function(){alert(1)});
$('p').trigger('click'); // 彈3次,即三個p的click都觸發(fā)了
$('p').triggerHandler('click'); // 僅彈1次,即只觸發(fā)第一個p的click
</script>
好了,是時候貼出jQuery.event.trigger的代碼了
復制代碼 代碼如下:
trigger: function( event, data, elem, onlyHandlers ) {
// Event object or event type
var type = event.type || event,
namespaces = [],
exclusive;
......
}
這就是jQuery.event.trigger的定義,省略了大部分。下面一一列舉
復制代碼 代碼如下:
if ( type.indexOf("!") >= 0 ) {
// Exclusive events trigger only for the exact event (no namespaces)
type = type.slice(0, -1);
exclusive = true;
}
這一段是為了處理.trigger('click!')的情形,即觸發(fā)非命名空間的事件。變量exclusive掛在事件對象上后在jQuery.event.handle內(nèi)使用。舉個例子
復制代碼 代碼如下:
function fn1() {
console.log(1)
}
function fn2() {
console.log(2)
}
$(document).bind('click.a', fn1);
$(document).bind('click', fn2);
$(document).trigger('click!'); // 2
為document添加了兩個點擊事件,一個是具有命名空間的"click.a",一個則沒有"click"。使用trigger時參數(shù)click后加個嘆號"!"。從輸出結(jié)果為2可以看出不觸發(fā)命名空間的事件??偨Y(jié)一下:
.trigger('click') 觸發(fā)所有的點擊事件
.trigger('click.a') 僅觸發(fā)“click.a” 的點擊事件
.trigger('click!') 觸發(fā)非命名空間的點擊事件
接著看
復制代碼 代碼如下:
if ( type.indexOf(".") >= 0 ) {
// Namespaced trigger; create a regexp to match event type in handle()
namespaces = type.split(".");
type = namespaces.shift();
namespaces.sort();
}
這段就很好理解了,就是對.trigger('click.a')的處理,即對具有命名空間事件的處理。
接著看
復制代碼 代碼如下:
if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {
// No jQuery handlers for this event type, and it can't have inline handlers
return;
}
對于一些特殊事件如"getData"或?qū)τ谝呀?jīng)觸發(fā)過的事件直接返回。
往下
復制代碼 代碼如下:
event = typeof event === "object" ?
// jQuery.Event object
event[ jQuery.expando ] ? event :
// Object literal
new jQuery.Event( type, event ) :
// Just the event type (string)
new jQuery.Event( type );
有三種情況
,event 本身就是jQuery.Event類的實例
,event是個普通js對象(非jQuery.Event類的實例)
,event是個字符串,如"click"
續(xù)
event.type = type;
event.exclusive = exclusive;
event.namespace = namespaces.join(".");
event.namespace_re = new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)");
需要注意exclusive/namespace/namespace_re掛到了event上了,在jQuery.event.handle中可以用到(事件命名空間)。
往下是
復制代碼 代碼如下:
// triggerHandler() and global events don't bubble or run the default action
if ( onlyHandlers || !elem ) {
event.preventDefault();
event.stopPropagation();
}
onlyHandlers 只在 .triggerHandler用到了,即不觸發(fā)元素的默認行為,且停止冒泡。
下面是
復制代碼 代碼如下:
// Handle a global trigger
if ( !elem ) {
// TODO: Stop taunting the data cache; remove global events and always attach to document
jQuery.each( jQuery.cache, function() {
// internalKey variable is just used to make it easier to find
// and potentially change this stuff later; currently it just
// points to jQuery.expando
var internalKey = jQuery.expando,
internalCache = this[ internalKey ];
if ( internalCache && internalCache.events && internalCache.events[ type ] ) {
jQuery.event.trigger( event, data, internalCache.handle.elem );
}
});
return;
}
這里是個遞歸調(diào)用。如果沒有傳elem元素,那么從jQuery.cache里取。
接著是
復制代碼 代碼如下:
// Don't do events on text and comment nodes
if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
return;
}
屬性,文本節(jié)點直接返回。
下面是
復制代碼 代碼如下:
// Clone any incoming data and prepend the event, creating the handler arg list
data = data != null ? jQuery.makeArray( data ) : [];
data.unshift( event );
先將參數(shù)data放入數(shù)組,event對象放在數(shù)組的第一個位置。
接著是
復制代碼 代碼如下:
// Fire event on the current element, then bubble up the DOM tree
do {
var handle = jQuery._data( cur, "handle" );
event.currentTarget = cur;
if ( handle ) {
handle.apply( cur, data );
}
// Trigger an inline bound script
if ( ontype && jQuery.acceptData( cur ) && cur[ ontype ] && cur[ ontype ].apply( cur, data ) === false ) {
event.result = false;
event.preventDefault();
}
// Bubble up to document, then to window
cur = cur.parentNode || cur.ownerDocument || cur === event.target.ownerDocument && window;
} while ( cur && !event.isPropagationStopped() );
這段代碼很重要,做了以下事情
,取handle
,執(zhí)行
,執(zhí)行通過onXXX方式添加的事件(如onclick="fun()")
,取父元素
while循環(huán)不斷重復這四步以模擬事件冒泡。直到window對象。
接下是
復制代碼 代碼如下:
// If nobody prevented the default action, do it now
if ( !event.isDefaultPrevented() ) {
var old,
special = jQuery.event.special[ type ] || {};
if ( (!special._default || special._default.call( elem.ownerDocument, event ) === false) &&
!(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
// Call a native DOM method on the target with the same name name as the event.
// Can't use an .isFunction)() check here because IE6/7 fails that test.
// IE<9 dies on focus to hidden element (#1486), may want to revisit a try/catch.
try {
if ( ontype && elem[ type ] ) {
// Don't re-trigger an onFOO event when we call its FOO() method
old = elem[ ontype ];
if ( old ) {
elem[ ontype ] = null;
}
jQuery.event.triggered = type;
elem[ type ]();
}
} catch ( ieError ) {}
if ( old ) {
elem[ ontype ] = old;
}
jQuery.event.triggered = undefined;
}
}
這一段是對于瀏覽器默認行為的觸發(fā)。如form.submit(),button.click()等。
注意,由于Firefox中鏈接的安全性限制,jQuery對鏈接的默認行為都統(tǒng)一為不能觸發(fā)。即不能通過.trigger()使鏈接跳轉(zhuǎn)。
您可能感興趣的文章:
- jQuery如何使用自動觸發(fā)事件trigger
- 解決jquery中動態(tài)新增的元素節(jié)點無法觸發(fā)事件問題的兩種方法
- JQuery自動觸發(fā)事件的方法
- jQuery實現(xiàn)長按按鈕觸發(fā)事件的方法
- jquery實現(xiàn)勾選復選框觸發(fā)事件給input賦值
- jquery實現(xiàn)input輸入框?qū)崟r輸入觸發(fā)事件代碼
- JQuery文本改變觸發(fā)事件如聚焦事件、失焦事件
- JQuery觸發(fā)事件例如click
- jquery實現(xiàn)按Enter鍵觸發(fā)事件示例
- jquery實現(xiàn)輸入框?qū)崟r輸入觸發(fā)事件代碼
相關(guān)文章
使用ajax+jqtransform實現(xiàn)動態(tài)加載select
本文給大家介紹了使用ajax+jqtransform實現(xiàn)動態(tài)加載select,效果非常的不錯,這里推薦給大家,有需要的小伙伴直接拿走使用。2014-12-12jQuery插件form-validation-engine正則表達式操作示例
這篇文章主要介紹了jQuery插件form-validation-engine正則表達式操作,結(jié)合實例形式分析了jQuery插件form-validation-engine進行正則驗證操作的相關(guān)技巧,需要的朋友可以參考下2017-02-02JQuery+CSS提示框?qū)崿F(xiàn)思路及代碼(純手工打造)
純手工打造、兼容性還哦可、可移植任何項目感興趣的朋友可以學習下,希望對你的jquery提升有所幫助2013-05-05JQuery頁面圖片切換和新聞列表滾動效果的具體實現(xiàn)
這篇文章介紹了JQuery頁面圖片切換和新聞列表滾動效果的具體實現(xiàn),有需要的朋友可以參考一下2013-09-09jQuery 獲取select選中值及清除選中狀態(tài)
這篇文章主要介紹了jQuery 獲取select選中值及清除選中狀態(tài)的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-12-12Jquery實現(xiàn)$.fn.extend和$.extend函數(shù)
這篇文章主要介紹了Jquery實現(xiàn)$.fn.extend和$.extend函數(shù)的相關(guān)資料,需要的朋友可以參考下2016-04-04