各位同學,我們今天要解的題目如下:

ASP.NET網頁中有一個控件產生的DataGrid,其在<TR>上放入了onclick事件,以達到點選該列的任何位置都會觸發特定事件,但如果其中有個<TD>裡希望在onclick時執行特定邏輯,而不要觸發原本<TR>上的onclick,要怎麼做?

面對以上的例子,低年級同學可能會想: 那就不要放onclick在TR上,每個TD上放一個onclick,不就可以任意控制? 這個構想不能說錯,但有點囉嗦。試想,如果一個TR裡有30個TD,豈不要寫29個onclickA加1個onclickB,更何況題目中的TR onclick是控件放的,怎麼做等於干擾了原本的設計。

比較有效率的方法,是讓指定的TD變成整個TR onclick事件的【特例】,這樣程式會比較簡潔。要做到所謂的事件邏輯中的特例,就不能不提到Event Bubbling的觀念,當某個容器元素(如<TR>)包著另一個子元素(如<TD>),使用者按下滑鼠,這兩個元素的onclick事件會被"先後"觸發,這個觀念在UI相關的程式開發中都有,中年級同學應該都有學過。參考資料

由於onclick事件的觸發順序會是先TD再TR,因此我們可以為TD指定另外的onclick事件,並在其中要求停止觸發後續的onclick事件。在IE中的寫法是window.event.cancelBubble = true;,Firefox中則可以用e.stopPropagation();

我寫成以下的例子,有興趣的同學可以實驗一下:

<html><body>
<table border="1">
<tr onclick="rowClick();">
<td>AA</td>
<td><input type="button" value="BB" onclick="btnClick()" /></td>
<td><span onclick="cellClick(event);">CC</span></td>
</tr>
</table>
<script type="text/javascript">
function rowClick() { alert("ROW!"); }
function cellClick(evt) { 
    alert("CELL!"); 
    if (window.event) //for IE
        window.event.cancelBubble = true;
    else //for Firefox
        evt.stopPropagation();
}
function btnClick() { alert("BUTTON!"); }
</script>
</body></html>

Comments

# by Ammon

在.net control產生的每一個 tr 上下onclick, 首推 jQuery 啊! 取消 Event Bubbling 也只要 return false; $('tr').click(function(){ alert("ROW!"); }); $('td>span').click(function(){ alert("CELL"); return false; });

# by Jeffrey

to Ammon, 謝謝補充,閣下果真是Javascript牛人。 這段Code也要寫給還不知jQuery滋味的同事看,所以我忍著不用jQuery寫範例(手好癢~~~)。自從學會jQuery,寫Javascript時若不能$( )一下,簡直是種折磨!

# by ethan

您好 我想請問一下喔 如果在一個元素裡面,有一個 onclick 事件和一個 ondblclick 事件 在我雙擊該元素的時候,有辦法不要處理 onclick 而只處理 ondblclick 嗎? 謝謝!

# by Jeffrey

to ethan, 邏輯有點怪,onclick會在ondblclick之前會被觸發,而onclick被觸發時,並無法得知這否是Double Click。要實現這個構想可能得由ondblclick來壓抑(suppress)onclick發作,也就是onclick時,先不立即動作,利用setTimeout設定500ms後才動作,如果500ms還沒到,ondblclick被觸發,就可以修改某個旗標,讓原本預定500ms後要做的onclick事件取消。 這是我想到的做法,看看還有沒有人有其他點子。

# by ethan

jeffery, 謝謝你的提示!!依照你說的觀念,我已經寫出來了=) 如果您有興趣,不妨參考一下我的程式碼 http://www.ethantw.net/wordpress/2008/10/onclick-ondblclick-kungyung/

Post a comment