2013-12-20 110 views
0

我正在開發/現在已經開發了一些系統,我也碰到過在我的編程querk,我似乎代表團所有我的jQuery函數的文檔,像這樣:的Javascript代表團最佳實踐

$(document).on('click', '.modal-editor', function() { 
    //code 
}); 

$(document).on('click', '.another-class', function() { 
    //code 
}); 

$(document).on('click', '#another-id', function() { 
    //code 
}); 

這有什麼不對嗎?

UPDATE:

好了,所以在本質上沒有什麼不妥,直到:

  1. 的應用達到哪裏代表團需要更本地化,以防止放緩UI規模。 「發生的每個事件都需要針對e.target和文檔之間的每個元素運行每個選擇器」

  2. 這樣的委派會增加使用嵌套函數時傳播等意外行爲的機會。

回到我的問題(最佳實踐),最佳做法是將事件委託給最接近靜態元素以儘量避免上述情況。

+1

我不這麼認爲......你應該沒事... –

+3

這可能會成爲一個問題的規模;沒有一攬子答案。 – Mathletics

+0

關於您的更新,不,我不會等待那裏出現性能問題。 jQuery擺脫了'.live()'方法的原因。即使他們眼下沒有明顯的好處,對於明智的做法也有一些東西要說。 –

回答

3

是的。在本身不存在,n要真的,但委託從document(DOM的根)的所有事件不意味着所有點擊事件,包括那些你會被至少部分地處理並不感興趣:

$(document).on('click', '$another-id', function(){}); 

是一個特別糟糕的主意,在這方面:你的單一元素之後的時候,但如果我在身體的任意位置單擊,JQ會做這樣的事情:

if (event.target.id == 'another-id') 
{ 
    return callback.call(event.target, $(event));//where callback is the anonymous function you passed to on 
} 
return event; 

所以所有點擊事件導致函數調用。這可能會降低您的用戶界面。
絕不應該停止委託事件,但明智地綁定聽衆。例如,如果您想要使用的所有DOM元素都包含在#container div中,那麼請將您的聽衆綁定到那裏。如果要處理導航事件,請將偵聽器綁定到包含所有導航元素的節點之後
除此之外,如果您取消某個事件,但未成功返回stopPropagation,則該事件仍將最終調用所有導航元素你的其他聽衆可能會排隊。 Returnign false也會造成麻煩,視爲,在jQ中,return false被翻譯爲e.preventDefault(); e.stopPropagation()

$(document).on('click', 'a', function(){});//is called for all links 
$(document).on('click', 'a.navigation', function(){});//is called for navigation 

:因此,與嵌套元素打交道時,如果你想處理在你的網頁鏈接點擊,但也像<a class='navigation'>元素,無論是處理器可能被稱爲,根據所使用的選擇要慎重哪個會被首先調用?你會想要在給定的情況下使用?有閃失這裏,不應該有:

$('#navContainer').on('click', 'a.navigation', function(){});//is called for all links 

至少使事情稍微更安全,更清晰,更輕了。

如果你想委託的事件時,使用ID選擇器和元素在DOM已經存在,不委託

$('#another-id').on('click', function(){}); 

較短,並有可能甚至會更快呢

+0

這是一個公平的觀點,所以不僅我前瞻性地放慢了我的UI,增加了冒泡的機會? – Edward

+1

@Edward:我編輯了一些,但基本上是的:你陷入事件循環,可能會減慢UI,並且沒有_certainty_事件處理程序將首先被調用,所以你不知道哪個回調函數會對什麼元素髮生什麼事件作出反應,特別是對於冒泡可能導致問題的嵌套元素 –

1

沒有什麼不對您的代碼,

$(document)不必是地方總是在事件委託,該選擇是指以被動態地添加元素上的最接近的父元素:

語法:

$(closest parent selector).on('event','target selector', function(){ 
}); 

您還可以使用document.body

$(document.body).on('event','target selecor',function(){ 
}); 

邊注:對於現有的DOM元素,您可以使用正常的點擊事件。

$('selector').click(function(){ 
}); 

OR

$('selector').on('click',function(){ 
}); 

欲瞭解更多信息,請參閱.on() API文檔。

1

如果您希望將特定事件應用於多個元素,並且每個元素都沒有自己的事件處理程序,那麼授權非常棒。在上面的例子中,前兩種方法很可能。

在哪裏只會有一個元素與理論上的標準相匹配,這可能會影響性能,具體取決於文檔的大小,因爲每個事件都必須針對處理程序過濾器進行測試,以查看它是否它火柴。另外,如果每個方法都作爲委託添加,並且您經常加載和上傳頁面的各個部分,那麼這些事件將比它們所屬的頁面上的元素更長。

您可以將您的處理程序委託給文檔元素以外的其他元素,例如周圍的div或其他可能在此類場景中的東西。或者使用事件命名空間來確保事件不會被多次添加。

4

「這有什麼問題嗎?」

是的。發生的每個事件都需要針對e.targetdocument之間的每個元素運行每個選擇器。這是不必要的昂貴。

基本上是這樣簡單的僞代碼:

// start on the e.target 
var node = e.target; 

// For the target and all its ancestors until the bound element... 
while (node && node !== this) { 

    // ...test the current node against every click selector it was given 
    for (var i = 0; i < click_selectors.length; i++) { 

     // If a selector matches... 
     if ($(node).is(selector)) { 
      // ...run the handler for that selector 
     } 
    } 
    node = node.parentNode; 
} 

另外,如果你的代碼,或者您加載一些其他的代碼綁定e.targetdocument之間的處理程序,並調用e.stopPropagation(),該事件將永遠不會到達document ,所以你的不會開火。

保持代表團儘可能接近目標元素要好得多。並且主要用於動態加載的元素,因爲它會增加額外的開銷,特別是在事件迅速啓動的情況下。