js時間冒泡

   在用jQuery的事件綁定時,會用到on()、bind()、live()、 delegate()這幾個方法,但對他們的區別缺從未注意過,現稍總結一下,如有錯誤,歡迎指正。

      參考文檔:
http://blog.csdn.net/xxd851116/article/details/8646899
http://www.jb51.net/article/57827.htm
http://www.jb51.net/article/67166.htm
http://api.jquery.com/on/
http://api.jquery.com/delegate/
http://api.jquery.com/bind/
http://api.jquery.com/live/
http://www.cnblogs.com/aaronjs/p/3481075.html
http://blog.jquery.com/2016/05/20/jquery-1-12-4-and-2-2-4-released/
http://blog.jquery.com/2016/06/09/jquery-3-0-final-released/

DOM樹

      我們先種一顆DOM樹,來說明接下來將要講到的事件冒泡,圖片引用自:
http://blog.csdn.net/xxd851116/article/details/8646899
這裏寫圖片描述

在操縱DOM的語境中,document是根節點。

事件冒泡

      該小節內容均引自:
http://blog.csdn.net/xxd851116/article/details/8646899

當我們點擊一個a鏈接時,其觸發了鏈接元素的單擊事件,該事件會引發所有已綁定到該元素的單擊事件上的函數的執行——這就是事件觸發

      如下代碼,一個用戶單擊操作會觸發alert函數的執行。

$('a').bind('click', function() { alert("That tickles!") });  
  • 1

      該事件觸發過程用圖片表示如下,圖片引用自:
http://blog.csdn.net/xxd851116/article/details/8646899
這裏寫圖片描述

而在上圖執行之後,click事件會接着向樹的根方向傳播,廣播到父元素,然後是每級的祖先元素,只要是它的某個後代元素上的單擊事件被觸發,事件就會傳給它————這就是事件冒泡

      整個過程如下圖所示,圖片引用自:
http://blog.csdn.net/xxd851116/article/details/8646899
這裏寫圖片描述

官方說明

      明白了事件冒泡的概念,我們正式進入jQuery的事件綁定與事件委託(也成事件代理)的講解中。

      首先我們從jQuery的官網上看一下關於這4個方法的說明:

live():jQuery1.7之後棄用 (故本文不再講解這個方法)
bind(): 動態添加的元素無法使用該方法綁定事件
delegate():jQuery1.7之後被on()取代
on(): jQuery1.7之後引入,支持事件綁定的全部功能。

      此外,jQuery官網上還說明的一點是:

In Internet Explorer 8 and lower, a few events such as change and submit do not natively bubble but jQuery patches these to bubble and create consistent cross-browser behavior.(引用自:
http://api.jquery.com/on/ ‘Direct and delegated events’)

      翻譯過來就是:

在IE8和之前的版本中,少數事件如change、submit不支持原生的事件冒泡,但是jQuery爲它們模擬了事件冒泡以此創建了一致的、跨瀏覽器的行爲。

      換句話說:jQuery模擬了所有的事件冒泡,使所有事件到支持事件冒泡併兼容所有瀏覽器

bind

bind()的用法

      bind()的用法如下:

//綁定單個事件
$( "#foo" ).bind( "click", function() {
  alert( "User clicked on 'foo.'" );
});
//綁定多個事件
$( "#foo" ).bind( "mouseenter mouseleave", function() {
  $( this ).toggleClass( "entered" );
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

bind()存在的問題

      我們用一個能夠看出bind()問題的代碼來說明

$("div").bind("click", function () {
     alert($(this).text());
 })
  • 1
  • 2
  • 3

      這段代碼的作用是:掃描整個html文檔找出所有的$(‘div’)元素,並把alert函數綁定到每個元素的click事件上。

      從這個代碼中,我們可以發現bind()有如下問題:

    1、這裏用到了隱式迭代,如果匹配到的元素特別多的時候,比如頁面中有100個div元素,就得執行綁定100次。對於大量元素來說,影響到了性能。但是如果是id選擇器,因爲id唯一,用bind()方法就很快捷了。
    2、bind()只能給調用它的時候已經存在的元素綁定事件,對於動態添加的元素無法使用該方法綁定事件。
    3、官網建議使用on()來替代bind()

delegate

      上述bind()的前2個問題,用delegate可以解決。

delegate()的用法

      delegate()的用法如下:

$('#container').delegate('a', 'click', function() { alert("That tickles!") }); 
  • 1

      這段代碼的作用是:掃描文檔查找$(‘#container’)</code>,並使用click事件和’a’這一CSS選擇器作爲參數把alert函數綁定到<code>$(‘#container’)上。任何時候只要有事件冒泡到$(‘#container’)上,它就查看該事件是否是click事件,以及該事件的目標元素是否與CCS選擇器(即’a’元素)相匹配。如果兩種檢查的結果都爲真的話,它就執行函數。

delegate()的特點

    1、直接將目標元素選擇符("a")、事件("click")及處理程序與“委託方”$("#container")綁定,不額外收集元素、事件傳播路徑縮短、語義明確;
    2、支持鏈式調用,即支持如$("table").find("#info").delegate(...)的代碼來精確控制;
    3、使用事件委託時,如果註冊到目標元素上的其他事件處理程序使用.stopPropagation()阻止了事件傳播,那麼事件委託就會失效。

使用delegate()而不是bind()的原因

1、爲了把處理程序附加到可能還未存在於DOM中的DOM元素之上。因爲bind是直接把處理程序綁定到各個元素上,它不能把處理程序綁定到還未存在於頁面中的元素之上。

2、如果你運行了$(‘a’).bind(…),而後新的鏈接經由AJAX加入到了頁面中,則你的bind處理程序對於這些新加入的鏈接來說是無效的。而另一方面delegate則是被綁定到另一個祖先節點上,因此其對於任何目前或是將來存在於該祖先元素之內的元素都是有效的。

3、或者爲了把處理程序附加到單個元素上或是一小組元素之上,監聽後代元素上的事件而不是循環遍歷並把同一個函數逐個附加到DOM中的100個元素上。把處理程序附加到一個(或是一小組)祖先元素上而不是直接把處理程序附加到頁面中的所有元素上,這種做法帶來了性能上的好處。

(引用自:http://blog.csdn.net/xxd851116/article/details/8646899

on

      通過查看jQuery的源代碼(我查看的版本是1.12.4),可以發現無論bind()還是delegate()都是通過on()方法實現的,只是參數不同,如下圖:
這裏寫圖片描述

      on()的官方API描述如下:

.on( events [, selector ] [, data ][, handler])
  • 1

官網建議從jQuery1.7開始,儘量使用on()方法來綁定事件,可以不必再使用delegate()或bind()方法了。

直接綁定和事件委託

      我們直接看官網對直接綁定和事件委託的介紹

      大多數瀏覽器的事件冒泡,都是從文檔的最深、最內層發生事件的元素(也稱爲event target——事件目標),一路向上到達body或document元素上。在IE8和之前的版本上,少數事件例如change、submit不支持原生的事件冒泡,但jQuery模擬並創建了一致的、跨瀏覽器的事件冒泡行爲。

      

      如果on()方法的selector 參數爲空,事件處理程序就被稱爲直接綁定。每當在被綁定元素上(如下例中被綁定的document元素,譯者注)發生事件時,無論這個事件發生在這個元素上還是從內層元素經冒泡而來,該處理程序都會被調用。

      並且,如果on()方法的selector 參數爲空,它與bind()方法相同——只能綁定頁面已有元素的事件。

      下面我們用代碼說明什麼是直接綁定

<body>
<div>
        這是一個div
        <button>點擊</button>
</div>
<script type="text/javascript">
        $(function(){
            //將click事件綁定在document對象上,
            //頁面上任何元素髮生的click事件都冒泡到document對象上得到處理
            //從而調用事件處理程序
            //本例爲了簡單綁定到了document,實際上綁定到那個元素上都有類似效果
            $(document).on("click",function(e){
               console.log(e.target.tagName + " is clicked")
            })  
        })
    </script>
</body>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

      頁面執行效果如下圖:
這裏寫圖片描述

      如果on()方法的selector 參數不爲空,事件處理程序就被稱爲委託。當事件直接發生在被綁定的元素上(如下例中綁定到document上,譯者注)時,該程序不會被調用,而只有當事件發生在與選擇器匹配的內部元素上(如下例中click事件發生在button上,譯者注)時,纔會調用該程序。

      

jQuery的事件委託是將事件從事件的發生者(即event target,譯者注)一直向上冒泡到綁定了事件處理程序的元素上(例如從最內層元素向上冒泡到最外層元素),併爲冒泡“沿路”過程中匹配的所有選擇器執行事件處理程序。

      下面我們用代碼說明什麼是委託

<body>
    <div>
        這是一個div
        <button>點擊</button>
    </div>
    <script type="text/javascript">
        $(function(){
            //將click事件綁定在document對象上,
            //並傳入第二個可選參數:selector
            //當事件冒泡到document對象時,檢測事件的target,
            //如果與傳入的選擇符(這裏是button)匹配,就調用事件處理程序即觸發事件,否則不觸發。
            $(document).on("click","button",function(e){
                console.log(e.target.tagName + " is clicked")
            })
        })
    </script>
    </body>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

      面執行效果如下圖:
這裏寫圖片描述

事件處理程序只會被綁定到當前已被選定的元素上(如上例中的document元素上,譯者注),這些元素在調用on()方法時必須已經存在——同bind()。

爲了確保這些元素已經存在並能被選中,請將代碼放置到</body>標籤之前或者在$(function(){ ... })內執行事件綁定。或者,使用事件委託來綁定事件處理程序。

      

事件委託的優點
      1、能處理來自於內層子元素的事件,這些內層子元素是在稍後時間裏被添加的文檔中的。通過選擇一個在綁定事件委託處理程序時肯定存在的元素,就可以使用事件委託來避免 需要頻繁的添加和刪除事件處理程序的操作。
      這個元素可以是MVC模式下的一個視圖容器元素或者是document元素(如果事件處理程序需要監聽文檔中的全部冒泡事件)。在加載任何html代碼之前,document元素已經在html文檔的頭部存在了,所以無需等待dom ready就可以在document這個元素上綁定事件了,這是安全可靠的。

      2、除了可以處理尚未創建的內層子元素的事件,事件委託的另一個優點是:當需要監聽很多元素時,事件委託的性能更好。

例如:有一個1000行數據的表格,下面的代碼就是將一個事件處理程序綁定到這1000個元素上,事件綁定需要執行1000次。

$( "#dataTable tbody tr" ).on( "click", function() {
  console.log( $( this ).text() );
});
  • 1
  • 2
  • 3

      事件委託方式(如下代碼)是將事件處理程序綁定到一個元素上,即tbody上,事件只需向上冒泡一級(從被點擊的tr元素到tbody元素)。事件只需綁定一次,然後採用事件冒泡來觸發事件。

$( "#dataTable tbody" ).on( "click", "tr", function() {
  console.log( $( this ).text() );
});
  • 1
  • 2
  • 3

以上內容翻譯自:http://api.jquery.com/on/ 《Direct and delegated events》一節

總結

1.選擇器匹配到的元素比較多時,不要用bind()迭代綁定
2.用id選擇器時,可以用bind()
3.需要給動態添加的元素綁定時,用delegate()或者on()
4.用delegate()和on()方法,dom樹不要太深
5.儘量使用on()來代替delegate()和bind()
6.在需要爲較多的元素綁定事件的時候,優先考慮事件委託,可以帶來性能上的好處
7.bind()和delegate()都是通過on()方法實現的,只是參數不同——當on()的selector參數爲空時,其效果完全等同於bind();當selector參數不爲空時,其效果完全等同於delegate();
8.使用.on()方法時,事件只會綁定到$()函數的選擇符表達式匹配的元素上(上面例子中,爲了簡單綁定到了document),因此可以精確地定位到頁面中的一部分,從而減少事件冒泡的開銷。

附 關於各版本對瀏覽器的兼容

引用jQuery官網的原話說明一下各版本對瀏覽器的兼容問題

1.x 版本支持 IE 6/7/8, 2.x 版本不支持 IE 6/7/8

1.12.4下載地址:
https://code.jquery.com/jquery-1.12.4.js
https://code.jquery.com/jquery-1.12.4.min.js

2.2.4下載地址:
https://code.jquery.com/jquery-2.2.4.js
https://code.jquery.com/jquery-2.2.4.min.js

(引用自:http://blog.jquery.com/2016/05/20/jquery-1-12-4-and-2-2-4-released/ )

1.12和2.2版本仍會提供重要補丁,但不會新增功能或做重大修改。3.x版本將是jQuery未來的主流版本,如果仍想在IE6-8上使用jQuery,請使用1.12的最新版本

(引用自:http://blog.jquery.com/2016/06/09/jquery-3-0-final-released/)

(function () { ('pre.prettyprint code').each(function () { var lines = (this).text().split(\n).length;var numbering = $('
    ').addClass('pre-numbering').hide(); (this).addClass(hasnumbering).parent().append( numbering); for (i = 1; i
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章