1. 程式人生 > >用jQuery繫結事件到動態建立的元素上

用jQuery繫結事件到動態建立的元素上

jQuery最常用的一個功能就是對DOM的操作,與之相關的比如對事件的繫結和Ajax動態內容載入。當我們繫結事件到Ajax load回來的內容上或其他動態建立的元素上時會發現事件沒響應,和你預想的結果不同,就像沒這會事兒一樣。這是前端開發 非常蛋疼的問題。jQuery在1.3的版本里面引入了.live()方法,後來jQuery團隊有在這基礎上加入了.delegate().on()方法來解決這種尷尬的局面。大家可以根據你自己專案使用的jQuery版本不同選擇下面的不同方法解決這個問題。

舉個例子,假設我們有這樣一個頁面:

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script>
  $(document).ready(function(){
    $('button').click(function(){
      $('ol').append('<li><a href="#">動態增加的節點</a></li>');
    });
  });
</script>
</head>
<body>
<ol>
  <li>
    <a href="#">靜態節點連線</a>
  </li>
</ol>
<button>增加節點</button><pre name="code" class="html">// 簡單粗暴,直接繫結到DOM物件
$(document).on('click', 'a', function(){
    alert( $(this).text() );
    return false;
});
</body></html> 我們要解決的問題就是當點增加節點按鈕時動態在ol下面新增一個節點並且給這個節點繫結alert事件。

jQuery > 1.7.0 - 使用 .on() 事件繫結方法

如果你專案中使用的jQuery版本高於1.7.0,那麼推薦使用 .on() 方法,這個方法能夠直接繫結和代理事件。根據我們要實現的需求,我們需要使用代理事件來解決問題,也就是說我們吧事件的繫結交給父級元素,如何使用選擇器去實現事件繫結,來看一下程式碼:
//正確的做法
$('ol').on('click', 'a', function(){
    alert( $(this).text() );
});
我們是首先把事件繫結到父級元素/或者說是容器,再通過類選擇器找到"a"元素,然後把事件傳遞到動態建立的子元素上。我們必須要把事件繫結放到父級,不然像下面這樣的程式碼是不得行的:
//這樣的程式碼是不行的
$('a').on('click', function(){
    alert( $(this).text() );
});
如果是單個事件的繫結,那推薦使用這種事件繫結方法,這樣能夠很好的提升效能。
如果你不知道父類元素,你甚至可以繫結到 document 物件,不過這樣繫結像click這樣的簡單事件還行,換成是mousemove那可能對效能就有比較大的影響
// 簡單粗暴,直接繫結到DOM物件
$(document).on('click', 'a', function(){
    alert( $(this).text() );
});
更多關於 .on() 方法的介紹,請看官方說明http://api.jquery.com/on/

1.7 > jQuery >1.4.2  - 使用 .delegate() 事件繫結方法

.delegate()方法是 .on() 方法的前輩,在使用方法和效能方面都和.on() 方法類似,看程式碼:
// 具體父級元素繫結
$('ol').delegate('a', 'click', function(){
    alert( $(this).text() );
});
// 繫結到DOM物件
$(document).delegate('a', 'click', function(){
    alert( $(this).text() );
});
更多關於 .delegate() 方法的介紹,請看官方說明http://api.jquery.com/delegate/

1.4.2 > jQuery > 1.3 - 使用 .live() 事件繫結方法

.live()這個方法應該是屬於元老級的了,在jQuery 1.3的版本里面首次出現,就是為了解決繫結事件到動態元素的問題,這個在jQuery 1.7的版本里屬於是棄用的方法,jQuery 1.9以後就直接刪除了。
需要注意的是這個方法是實現原理是把事件繫結到document物件,然後通過選擇器和目標事件比較,如果匹配就觸發事件,前提條件要好保證事件的必須是連續正常執行的,如果其中一個事件出問題了,那所有的事件都不會觸發,另外,如果從document上取消事件繫結,那麼所有通過.live()方法繫結的事件都會取消。看程式碼:
// .live()實現動態繫結
$('li').live('click', function(){
    alert( $(this).text() );
});
更多關於 .live() 方法的介紹,請看官方說明http://api.jquery.com/live/

1.3 > jQuery - 使用 .bind() 事件繫結方法

如果你的專案還在使用jQuery 1.3~以前的版本,那好最升級一下,實在沒法升級,那就按照下面兩個方法來解決這個問題。
1、自己實現事件的傳遞,類似上面的.live()方法
$('ol').click(functino(event){
  if( $(event.target).is('a') ){
    alert( $(this).text() );
  }
});
2、明確的對動態載入的內容做操作,比如加上相應的css,重新繫結事件
$(document).ready(function(){
  $('button').click(function(){
   $('ol').append('<li class="dynamic-item"><a href="#">動態增加的節點</a></li>');
    // 然後在繫結新的事件
    $('a.dynamic-item:last').click(functino(){
      alert( $(this).text() );
      return false;
    });
  });
});

注:

不要把同一事件繫結到相同元素多次
儘量避免使用直接繫結到document物件,可以預先定義一個div,
比如<div id="ajax-loaded-container"></div>,
然後使用$('#ajax-loaded-container .my-link').click(...)這樣的方法去實現
需要動態繫結的css也可以在伺服器端的css檔案裡預先定義好