天天看點

jquery 建立的元素事件綁定問題

js的事件監聽跟css不一樣,css隻要設定好了樣式,不論是原來就有的還是新添加的,都有一樣的表現。而事件監聽不是,你必須給每一個元素單獨綁定事件。

常見的例子是處理表格的時候。每行行末有個删除按鈕,點了這個能夠删除這一行。

<table>

<tbody>

<tr>

<td>這行原來就有</td>

<td><buttonclass="del">删除</button></td>

</tr>

</tbody>

</table>

通常,我會這麼綁定

//已有删除按鈕初始化綁定删除事件

$(".del").click(function() {

$(this).parents("tr").remove();

});

對于在domready之前就存在的删除按鈕,一切都很完美。但如果在domready之後用js動态添加幾行,那新增的幾行中的這些按鈕都将失去任何作用。

如何解決這個問題?以下提供4種解決方案:

=============================

0号解決方案——onclick法

如果不顧結構與行為分離的準則的話,通常,我會這麼做。

注意,此時的deltr這個function必須是全局函數,得放jQuery(function($) {})外面,放裡邊就成局部函數了,html裡的onclick就調用不到了!

1.<td><buttononclickbuttononclick="deltr(this)">删除</button></td> 

1.jQuery(function($){   

2.   //添加行   

3.    $("#add2").click(function(){   

4.        $("#table2>tbody").append('<tr><td>新增行</td><td><button nclick="deltr(this)">删除</button></td></tr>')   

5.   });   

6.});   

7.//删除行的函數,必須要放domready函數外面   

8.function deltr(delbtn){   

9.    $(delbtn).parents("tr").remove();   

10.};  

1号解決方案——重複綁定法

即,在domready的時候就給已有的元素綁定事件處理函數,

而後當新增加的元素的時候再次綁定。

1.<td><buttonclassbuttonclass="del">删除</button></td> 

2.   //定義删除按鈕事件綁定   

3.   //寫裡邊,防止污染全局命名空間   

4.   function deltr(){   

5.        $(this).parents("tr").remove();   

6.   };   

7.   //已有删除按鈕初始化綁定删除事件   

8.    $("#table3 .del").click(deltr);   

9.   //添加行   

10.    $("#add3").click(function(){   

11.        $('<tr><td>新增行</td><td><button class="del">删除</button></td></tr>')   

12.           //在這裡給删除按鈕再次綁定事件。   

13.            .find(".del").click(deltr).end()   

14.            .appendTo($("#table3>tbody"));   

15.   });   

16.});  

2号解決方案——事件冒泡法

利用事件冒泡的原理,我們給這個按鈕的祖先元素綁定事件處理函數。

然後通過event.target這個對象來判斷,這個事件是不是我們要找的對象觸發的。

通常可以利用一些DOM屬性,比如event.target.className、event.target.tagName等之類的來判斷。

2.   //第四個表格的删除按鈕事件綁定   

3.    $("#table4").click(function(e) {   

4.       if (e.target.className=="del"){   

5.            $(e.target).parents("tr").remove();   

6.       };   

7.   });   

8.   //第四個表格的添加按鈕事件綁定   

9.    $("#add4").click(function(){   

10.        $("#table4>tbody").append('<tr><td>新增行</td><td><button class="del">删除</button></td></tr>')   

11.   });   

12.});  

3号解決方案——複制事件法

上面幾種方案可以說即便你沒有用到jQuery庫,你也能相對比較容易的實作。但這種方案相對依賴jQuery的程度更高。而且必須要求jQuery 1.2版以上。低版本jQuery需要插件。

上面兩個方案都是對删除函數動了很多腦筋,換了多種觸發、綁定的方式。這個方案不同,可以與平時純靜态的元素一樣在domready的時候綁定。但在我們添加新行的時候我們改動一下,不再想上面那樣拼接字元串來添加新行了。這回我們嘗試使用複制DOM元素的方式。并且複制的時候連同綁定的事件一起複制,複制完之後再用find之類的修改内部的元素。

同時,就像這個例子,如果你會把所有元素都删除光,那template這個模闆是必須的,如果不會删光,那就未必需要用template了。為了防止被誤删,此處我把template設了隐藏。

我使用了jQuery中特有的clone(true)

1..template{display:none;}  

1.<trclasstrclass="template">   

2.           <td>這裡是模闆</td>   

3.           <td><button class="del">删除</button></td>   

4.       </tr>   

5.       <tr>   

6.           <td>這行原來就有</td>   

7.           <td><button class="del">删除</button></td>   

8.       </tr>   

9.       <tr>   

10.           <td>這行原來就有</td>   

11.           <td><button class="del">删除</button></td>   

12.       </tr> 

2.   //第五個表格的删除按鈕事件綁定   

3.    $("#table5 .del").click(function() {   

4.        $(this).parents("tr").remove();   

6.   //第五個表格的添加按鈕事件綁定   

7.    $("#add5").click(function(){   

8.        $("#table5>tbody>tr:eq(0)")   

9.           //連同僚件一起複制   

10.            .clone(true)   

11.           //去除模闆标記   

12.            .removeClass("template")   

13.           //修改内部元素   

14.            .find("td:eq(0)")   

15.                .text("新增行")   

16.                .end()   

17.           //插入表格   

18.            .appendTo($("#table5>tbody"))   

19.   });   

20.});  

總評:

上面4種方案,各有優劣。

0号方案,結構與行為完全沒有分離,而且污染全局命名空間。最不推薦。是以我都不把它當作一個方案來看。但對于js初學者,可以用來項目救急。

1号方案,中規中矩,沒啥好也沒啥不好

2号方案,這種方法充分的發揮了js事件冒泡的優勢。而且效率最高。但同時由于這種方案無視了jQuery強大的選擇器,是以如果涉及的元素屬性要求過多就會比較麻煩了。你會徘徊在衆多if的條件的是非關系之中。後來我想起來,可以用jQuery中的$(event.target).is(selector)來作為條件。這樣可以極大提升開發效率,但略微降低執行效率。

3号方案,這是我認為最能展現結構與行為分離的思想的一種方案。但缺點也很明顯,對于jQuery依賴性過于高了,要不就自己寫一個複制連同僚件一起複制的函數,但這也顯然對于初學者來說異常困難。但從未來的趨勢的角度來看,還是很推薦使用這種方案的。

具體選用哪一個方案,沒有定數。具體看你的項目以及你js還有結構與行為分離的思想的掌握程度。最适合的才是最好的。

附加:

把3号方案改造成完美的結構行為分離的樣式。

首先,帶有template的是模闆元素。他是一切複制的源泉,為了防止被誤删,是以設為不可見。如果不會删除光,那麼這個模闆元素也是可選的。因為你可以複制任何一個已經存在的用于循環元素。

其次,給每個重複的元素加上一個repeat,友善用于删除按鈕找到這一級元素。這個是可選的,有時候并不需要。

最後是給每一個要修改的元素加上一個類,便于用find找到。比如我這裡就家了content類,新增

1.<tableidtableid="table6">   

2.   <tbody id="tbody6">   

3.       <tr class="template repeat">   

4.           <td class="content">這裡是模闆</td>   

5.           <td><button class="del">删除</button></td>   

6.       </tr>   

7.       <tr class="repeat">   

8.           <td class="content">這行原來就有</td>   

9.           <td><button class="del">删除</button></td>   

10.       </tr>   

11.       <tr class="repeat">   

12.           <td class="content">這行原來就有</td>   

13.           <td><button class="del">删除</button></td>   

14.       </tr>   

15.   </tbody>   

16.   <tfoot>   

17.       <tr>   

18.           <td> </td>   

19.           <td><button id="add6">添加</button></td>   

20.       </tr>   

21.   </tfoot>   

22.</table> 

2.   //第六個表格的删除按鈕事件綁定   

3.    $("#tbody6 .del").click(function() {   

4.        $(this).parents(".repeat").remove();   

6.   //第六個表格的添加按鈕事件綁定   

7.    $("#add6").click(function(){   

8.        $("#tbody6>.template")   

14.            .find(".content")   

18.            .appendTo($("#tbody6"))   

同樣,這段js也适用于如下的html結構

1.<ulidulid="tbody6">   

2.   <li class="template repeat">   

3.       <span class="content">這裡是模闆</span>   

4.       <span><button class="del">删除</button></span>   

5.   </li>   

6.   <li class="repeat">   

7.       <span class="content">這行原來就有</span>   

8.       <span><button class="del">删除</button></span>   

9.   </li>   

10.   <li class="repeat">   

11.       <span class="content">這行原來就有</span>   

12.       <span><button class="del">删除</button></span>   

13.   </li>   

14.</ul> 

本文轉自linzheng 51CTO部落格,原文連結:http://blog.51cto.com/linzheng/1081614

繼續閱讀