js和jquery中的觸發事件


改別人的坑,遇到jquery選擇器和fireEvent混用,不認識fireEvent方法報錯。

js的方法不能使用jquery的選擇器去調用。

1.fireEvent (IE上的js方法 )

我們來看看fireEvent跟onclick()觸發事件是否相同。看下面的代碼:

<ul onclick='alert(event.srcElement.innerHTML);'> 
<li id='id1'>i am one;</li> 
<li id='id2'>i am two;</li> 
<li id='id3'>i am three;</li> 
</ul> 
<button onclick='document.getElementById("id1").fireEvent("onclick")'>fireEvent !</button>

點擊button后,觸發ul的onclick事件,說明fireEvent會引起冒泡,而且沒有發生像onclick()提示“對象不支持此屬性或方法”,說明即使不添加id1的onclick事件也可以冒泡。 
由此可以看出,IE中的fireEvent方法類似模擬用戶的鼠標點擊行為,而不是單純的onclick。

觸發事件:

觸發事件,或稱模擬用戶動作。比如點擊,我們可以用代碼去模擬用戶點擊,達到的效果與真實的鼠標點擊是一樣的。

在 事件模塊的演變 我使用了dispatchEvent(標准) 和fireEvent(IE)來主動觸發事件。如下

 

... 
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觸發事件的核心方法是jQuery.event.trigger。它提供給客戶端程序員使用的觸發事件方法有兩個:.trigger/.triggerHandler 

代碼如下:


.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 ); 

}, 


可以看出,兩者都調用jQuery.event.trigger。調用時一個沒有傳true,一個傳了。傳了true的triggerHander就表示僅執行事件handler。 
此外還需注意一點區別:.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都觸發了 
$('p').triggerHandler('click'); // 僅彈1次,即只觸發第一個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!')的情形,即觸發非命名空間的事件。變量exclusive掛在事件對象上后在jQuery.event.handle內使用。舉個例子 

復制代碼代碼如下:

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時參數click后加個嘆號"!"。從輸出結果為2可以看出不觸發命名空間的事件。總結一下: 
.trigger('click') 觸發所有的點擊事件 
.trigger('click.a') 僅觸發“click.a” 的點擊事件 
.trigger('click!') 觸發非命名空間的點擊事件 
接着看 

復制代碼代碼如下:

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"或對於已經觸發過的事件直接返回。 
往下 

復制代碼代碼如下:

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" 
續 
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用到了,即不觸發元素的默認行為,且停止冒泡。 
下面是 

復制代碼代碼如下:

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


這里是個遞歸調用。如果沒有傳elem元素,那么從jQuery.cache里取。 
接着是 

復制代碼代碼如下:

// Don't do events on text and comment nodes 
if ( elem.nodeType === 3 || elem.nodeType === 8 ) { 
return; 


屬性,文本節點直接返回。 
下面是 

復制代碼代碼如下:

// Clone any incoming data and prepend the event, creating the handler arg list 
data = data != null ? jQuery.makeArray( data ) : []; 
data.unshift( event ); 


先將參數data放入數組,event對象放在數組的第一個位置。 
接着是 

復制代碼代碼如下:

// 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 
,執行 
,執行通過onXXX方式添加的事件(如onclick="fun()") 
,取父元素 
while循環不斷重復這四步以模擬事件冒泡。直到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; 


這一段是對於瀏覽器默認行為的觸發。如form.submit(),button.click()等。 
注意,由於Firefox中鏈接的安全性限制,jQuery對鏈接的默認行為都統一為不能觸發。即不能通過.trigger()使鏈接跳轉。 

(我是搬運工)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM