昨天在項目中發現一個問題:在DOM加載之後爲標籤綁定的事件對於新加進來的標籤並不起作用,通過查找發現事件並沒有綁定到新加入的標籤,因此今天特意總結一下這種問題的解決方案。
在jquery中,我們通常是在DOM加載完成後,再對元素綁定事件。以下面的情景爲例:製作一個表格,每一欄最後有個button可以刪除這一欄。然後還有一個添加按鈕,可以給表格添加一欄。代碼如下:
HTML代碼:
<table>
<thead>
<tr>
<th>學號</th>
<th>成績</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td>100</td>
<td>98</td>
<td><button class="del">刪除</button></td>
</tr>
<tr>
<td>101</td>
<td>88</td>
<td><button class="del">刪除</button></td>
</tr>
<tr>
<td>102</td>
<td>78</td>
<td><button class="del">刪除</button></td>
</tr>
</tbody>
</table>
<button class="add">添加</button>
jquery代碼:
$(function(){
$('.del').click(function(){
$(this).parents("tr").remove();
});
$('.add').click(function() {
$("<tr><td>103</td><td>68</td><td><button class='del'>刪除</button></td></tr>").appendTo('tbody');
});
});
上述代碼在DOM加載完後,通過jquery向class="del"
的刪除按鈕添加了一個click事件,用於刪除該欄。通過運行測試我們可以發現,給刪除按鈕添加的點擊事件對DOM中存在的前三欄是起作用,但是如果我們再點擊添加按鈕添加一欄,則新增的這一欄中的刪除按鈕並沒有綁定點擊事件。
js的事件監聽跟css不一樣,我們知道css只要設定好了樣式,不論是原來就有的還是新添加的,都有一樣的表現。而事件監聽不是,新增加的雖然設置了相同的class,但是並沒有綁定事件,你必須給每一個元素單獨綁定事件。
這種問題的處理方法主要有三種:
第一種:重複綁定
重複綁定法:DOM加載時,先對DOM中存在的元素進行事件綁定,每次新增的元素時,再對新增元素綁定一次事件,jquery代碼如下:
$(function(){
$('.del').click(deleteTr);
$('.add').click(function() {
$("<tr><td>103</td><td>68</td><td><button class='del'>刪除</button></td></tr>").find(".del").click(deleteTr).end().appendTo('tbody');
});
function deleteTr(){
$(this).parents("tr").remove();
}
});
第二種:使用onclick
這種方法就是直接在標籤上添加onclick屬性,如果不考慮結構與行爲分離的準則,這個方法也是能達到效果的:具體代碼如下:
HTML代碼:
<table>
<thead>
<tr>
<th>學號</th>
<th>成績</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td>100</td>
<td>98</td>
<td><button class="del" onclick='deleteTr(this)'>刪除</button></td>
</tr>
<tr>
<td>101</td>
<td>88</td>
<td><button class="del" onclick='deleteTr(this)'>刪除</button></td>
</tr>
<tr>
<td>102</td>
<td>78</td>
<td><button class="del" onclick='deleteTr(this)'>刪除</button></td>
</tr>
</tbody>
</table>
<button class="add">添加</button>
jquery代碼:
$(function(){
$('.add').click(function() {
$("<tr><td>103</td><td>68</td><td><button class='del' οnclick='deleteTr(this)'>刪除</button></td></tr>").appendTo('tbody');
});
});
function deleteTr(btn){
$(btn).parents("tr").remove();
}
這裏有一點需要注意就是onclick='deleteTr(this)'
中的deleteTr()
函數不能定義在$(function(){});
中,如果定義在$(function(){});
中,在解析HTML時,無法調用,因此需要定義在外面。
第三種:事件委託
通過查看jquery API文檔,發現有個live()事件,對live()事件的概述如下:“jQuery 給所有匹配的元素附加一個事件處理函數,即使這個元素是以後再添加進來的也有效。”但是很不幸的是,live()在jquery 1.7之後就不推薦使用了。
因此我們需要另外找路,通過查看文檔我們發現:.live() 方法能對一個還沒有添加進DOM的元素有效,是由於使用了事件委託:綁定在祖先元素上的事件處理函數可以對在後代上觸發的事件作出迴應。傳遞給 .live() 的事件處理函數不會綁定在元素上,而是把他作爲一個特殊的事件處理函數,綁定在 DOM 樹的根節點上。
既然知道了原理,那麼我們可以自己實現事件委託,我們不在button上直接綁定事件,而在把事件綁定在tbody上,通過判斷事件的目標event.target對象的某些屬性來判斷這個對象是不是我們要找的事件觸發的對象。
下面,我們通過className來判斷是否是我們的目標對象:
$(function(){
$('tbody').click(function(event){
if (event.target.className == "del") {
$(event.target).parents("tr").remove();
}
});
$('.add').click(function() {
$("<tr><td>103</td><td>68</td><td><button class='del'>刪除</button></td></tr>").appendTo('tbody');
});
});