1. 程式人生 > >事件委託和jQuery事件繫結

事件委託和jQuery事件繫結

事件委託

什麼是事件委託?用現實中的理解就是:100個學生在同一天的中午都要收取快遞,這100個學生難道都會在門口等著麼?不會,他們會委託門衛代收,然後門衛再逐個將包裹交到學生手中。在jQuery中我們會通過事件冒泡的特性,讓子元素的事件繫結到祖先元素上去,在祖先元素統一處理。如果我們專案中有個2000行的列表,每行都有個一個刪除button。如果使用.bind來處理,需要繫結2000次到刪除button上,這就好比2000個學生同時在校門口收快遞,會不斷的阻塞道路,還會出現怪異的行為。這種情況放到頁面上也是一樣,會導致介面效率低下,UI程式碼不夠靈活。而且這2000行資料肯定會用ajax分頁的,.bind無法繫結下一頁行中的刪除button。這就好比,新轉入的學生快遞員是無法驗證他的身份。這時我們就需要用到事件委託,將事件處理放到所有刪除button共有的祖先元素上,這個祖先元素根據自己的情況,可能是table標籤,可能是一個div標籤,也可能是body標籤。

利用jQuery實現事件繫結和解綁

jQuery中提供了.bind()和unbind()、.live()和die()、delegate()和undelegate()、on()和off()和one()來實現事件的繫結和解綁。下面我們將分別介紹這四種事件繫結和解綁的的方法。

.bind()和unbind()

.bind()給所有匹配的元素附件一個特定事件的處理的函式。假設我們有這麼一個需求:1、有個10行4列的table,每個單元格被單擊時,當前單元格背景變為藍色。2、點選某個button阻止單元格的預設事件和事件向上冒泡。實現如下:
table {
  width: 400px;
  height:240px;
  border:1px solid blue;
}

table td{
  border:1px solid black;
  width:100px;
}
$(document).ready(function(){
	var row = 10, col = 4;
    var $table = $("<table></table>");
	
  	for(var i=0;i<row;i++){
		var $tr = $("<tr></tr>");
		for(var j=0;j<col;j++){
			$("<td></td>").appendTo($tr);
		}
      	$table.append($tr);
    }
  	$("body").append($table);
  
  //使用.bind為每個匹配的click事件繫結處理函式
  $("table td").bind("click", function(event){<span style="white-space:pre">	</span>//(2)處
    $(this).css({backgroundColor:"#00F"});
  });
  
  $("table").bind("click", function(event){
    alert("ABC"); 
  });
  
  //新增一個button
  var $but = $("<button>阻止td的預設行為和事件向上冒泡</button>").appendTo("body");
  
  //阻止td的預設行為和事件向上冒泡
  $but.bind("click", function(){ 
      //這裡返回false有 兩個含義,阻止單元格的預設行為和事件向上冒泡
  	$("table td").bind("click", function(){ return false; }); //(1)處
  });
});
先給大家推薦一個線上編譯java、c、c++、JavaScript/HTML/CSS/等其它語言的線上編譯網站。http://c.runoob.com/。現在基本上能滿足我的學習需要,做個小示例和測試什麼的都是很方便的。 在推薦一個jQuery線上編譯器,本文示例以這個線上編譯器的效果為準。 解釋一下什麼是觸發事件的元素的預設行為和預設事件向上冒泡。 前者指的是:比如<a href="www.baidu.com"></a>,a標籤的click事件預設行為是開啟百度。我們可以在jQuery中使用 event.preventDefault(); 來阻止預設行為的發生。 後者指的是:阻止事件向祖先元素傳遞。比如點選單元格時,觸發了單元格祖先元素(table)的click事件,彈出了“ABC”。我們在jQuery中使用event.stopPropagation();阻止事件向上傳遞。 (1)處包含了這兩者的含義。 .unbind()。.bind()的反向操作,從每一個匹配的元素上刪除特定事件的處理函式。例如:
$("table td").unbind("click");<span style="white-space:pre">	</span>//只解綁click事件
$("table td").unbind();<span style="white-space:pre">		</span>//解綁所有事件

.live()和die()

我們來擴充套件一下.bind()和unbind()節中的示例,擴充套件功能為:點選一個按鈕在table的最後一行後新增一個新行,使這個新行具有和其它單元格一行的單擊行為。使用.live()就可以解決這個需求,.live()給所有匹配的元素添一個特定事件的處理函式,即使這個元素是後新增進來的。這樣就省去了在新增這個新行時,程式碼顯示的在呼叫.bind()。完整程式碼如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鳥教程(runoob.com)</title>
	<script  type="text/javascript" src="//cdn.bootcss.com/jquery/1.6.2/jquery.min.js"></script>
</head>
<body>
</body>
</html>
table {
  width: 400px;
  height:240px;
  border:1px solid blue;
}

table td{
  border:1px solid black;
  width:100px
}

$(document).ready(function(){
	var row = 10, col = 4;
    var $table = $("<table></table>");
	
  	for(var i=0;i<row;i++){
		var $tr = $("<tr></tr>");
		for(var j=0;j<col;j++){
			$("<td></td>").appendTo($tr);
		}
      	$table.append($tr); 
    }
  	$("body").append($table);
  
  //使用.live為每個匹配元素的click事件繫結處理函式
  $("table td").live("click", function(event){
    $(this).css({backgroundColor:"#00F"});
  });
  
  $("table").bind("click", function(event){
    alert("ABC"); 
  });
	
  //使用.die()解綁click事件函式
  var $but1 = $("<button>取消繫結事件</button>").appendTo("body");
  $but1.bind("click", function(){
    $("table td").die("click");
  })
});

其實.live()是.bind()的一種變體。但是實現原理兩者卻大不相同。.bind()是為每一個匹配的元素都繫結一個特定的處理函式。而.live()使用的是事件委託原理實現的,委託給了$(docuemnt)物件來處理,不會繫結到匹配的每個元素上,所以一個元素在之後新增進來,只要這個這個元素匹配選擇器($("table td"))就可以觸發繫結到$(document)物件的事件處理函式。 在我們上面的例子中,當點選新新增的行,會一次發生以下步驟: 1,生成一個事件物件,用來傳遞給處理函式 2,由於事件處理函式沒有直接繫結到新行上,事件向上冒泡(向上傳遞click事件) 3,事件不斷向上冒泡一直到DOM樹的根節點 4,觸發繫結到DOM樹根節點的事件處理函式 5,這個事件處理函式首先檢測事件源元素是否是匹配"table td"選擇器(這是為了防止其他其它標籤的事件也觸發.live()上繫結的函式)。 6,如果匹配就執行在.live上繫結的函式。 感興趣的同學可以瞭解一下事件冒泡和事件捕獲,瞭解了這兩個東西,才能更好的理解事件委託。這裡只是講解了.live()的用法和原理,具體細節請參見jQuery對.live()的說明。 由於.live()引數的特殊性,不支援鏈式呼叫等諸多不便原因,從jQuery1.4.3開始.live()和die() 不建議被使用,jQuery1.7以後的版本中.live()、die()函式已經被移除。如果使用jQuery1.7+版本話使用on()和off()來代替。如果使用的是1.7-版本的話建議使用delegate()和undelegate()來代替。已經被移除了還說這麼多是為了讓我們更好的理解jQuery的事件繫結和接下來將要介紹的兩組事件繫結函式。

delegate()和undelegate()

jQuery1.4.3開始.live()、die()不建議在被使用。而是建議使用支援鏈式呼叫、語義清晰、減少冒泡層次的.delegate()和undelegate()函式。我們可以通過選擇器指定將事件委託到那個元素上,而不是固定的DOM跟元素。使用者這兩個函式來改寫.live()和 die()節中的示例。程式碼如下(CSS程式碼同上,這裡只貼出了HTML和JS程式碼):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鳥教程(runoob.com)</title>
	<script  type="text/javascript" src="//cdn.bootcss.com/jquery/1.6.2/jquery.min.js"></script>
	<script id="jquery_183" type="text/javascript" class="library" src="/js/sandbox/jquery/jquery-1.8.3.min.js"></script>
</head>
<body>
</body>
</html>
$(document).ready(function(){
	var row = 10, col = 4;
    var $table = $("<table></table>");
	
  	for(var i=0;i<row;i++){
		var $tr = $("<tr></tr>");
		for(var j=0;j<col;j++){
			$("<td></td>").appendTo($tr);
		}
      	$table.append($tr); 
    }
  	$("body").append($table);
  
  //使用.delegate為每個匹配元素的click事件繫結處理函式
  $("table").delegate("td", "click", function(event){
    $(this).css({backgroundColor:"#00F"});
		return false;	//阻止預設行為和事件向上冒泡,不會彈出 “ABC”
  });
  
  $("table").bind("click", function(event){
    alert("ABC"); 
  });
  
	//使用undelegate()解綁click事件函式
  var $but1 = $("<button>取消繫結事件</button>").appendTo("body");
  $but1.bind("click", function(){
    $("table").undelegate("td", "click");
  })
});
通過上面的示例我們發現事件委託給了$("table"),delegate()的第一個引數是指只有$("table")下的td能觸發給$("table")的事件,$("table")下的其它子元素是不可以的,用於過濾觸發事件的元素。第二個引數事件型別。第三個引數事件處理函式。

on()和off()和one()

jQuery1.7+新增的新的事件處理函式on()、off()和one()整合了delegate()和undelegate()函式。並且提供了更靈活的事件繫結和解綁支援。使用on()、off()來改寫delegate()和undelegate()節的示例,程式碼如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鳥教程(runoob.com)</title>
	<script type="text/javascript" src="//cdn.bootcss.com/jquery/2.2.0/jquery.min.js"></script>
</head>
<body>
</body>
</html>
$(document).ready(function(){
	var row = 10, col = 4;
    var $table = $("<table></table>");
	
  	for(var i=0;i<row;i++){
		var $tr = $("<tr></tr>");
		for(var j=0;j<col;j++){
			$("<td></td>").appendTo($tr);
		}
      	$table.append($tr); 
    }
  	$("body").append($table);
  
  //使用.on為每個匹配元素的click事件繫結處理函式
  $("table").on("click.row", "td", function(event){
    $(this).css({backgroundColor:"#00F"});
    return false;	//阻止預設行為和事件向上冒泡,不會彈出 “ABC”
  });
  
  $("table").bind("click", function(event){
    alert("ABC"); 
  });
  
  //使用off()解綁click事件函式
  var $but1 = $("<button>取消繫結事件</button>").appendTo("body");
  $but1.bind("click", function(){
    $("table").off("click", "td");  
  })
});

off()第一個引數是事件型別,第二個引數是選擇器,第三個引數是事件處理函式。這裡第一個引數click.row比較特殊,click代表事件,row程式碼自定義的名稱空間,這樣在使用off()解綁事件時可用更靈活,比如上例中off("click", “td”)程式碼移除所有click事件,off(".row", "td")代表移除所有.row名稱空間下的事件。 one()為每個匹配的元素繫結一個一次性的事件處理函式,執行一次後,以後將不再觸發,相當於.bind()的一個特殊版(注意喲這裡是.bind的特殊版)。

總結

.bind()和off ()(off()是使用事件委託繫結事件中jQuery最建議使用的一個,比較典型,所以那它來和.bind()做比較)分別在什麼情況下使用呢? 兩個原則:DOM中多個元素需要繫結相同的事件處理函式時;DOM中未生成的元素需要繫結和DOM已有元素相同的事件處理函式時;滿足這兩個條時,使用off()。否則使用.bind(); 本文參考了jQuery文件和此部落格http://www.itnose.net/detail/6094205.html。以前在使用jQuery做事件繫結是,只是用過click() 函式繫結過單擊事件,今天看了一個JS框架,發現好多東西就沒有接觸過。和事件繫結相關的總結到此文章裡。一開始看jQuery文件也是一頭霧水,根本看不懂,最後到網上看了一些資料(比較通俗易懂的),在回頭看jQuery文件,發現Jquery文件就是jQuery文件,簡潔明瞭,資訊量大呀。先去民間看看,在能看懂官方的。