最近在看《javascript 進階程式》一書,寫自己的一些小心得體會,希望得到牛人們的指點,討論。
步入今天的正題,javascript事件處理函數,我們知道,javascript與HTML之間的互動是通過事件來實現的,事件就是使用者或瀏覽器自身執行的某種動作,比如click、mounseover、load……,而響應事件的函數就叫做事件處理函數(或事件接聽程式)。
<input type="button" value="click me" onclick="alert('click me')" />
這裡我們把事件處理常式直接內聯到了HTML代碼中,但這對於我們閱讀代碼極不友好,下面我們把事件處理常式分離出去,如下:
function showMessage() {alert("click me");}
然後我們在HTML代碼中去調用:
<input type="button" value="click me" onclick="showMessage()" />
在HTML中指定事件處理函數有兩個缺點:
1. 存在時差的問題,以上面的例子來說,假設showMessage()函數定義在頁面的最底部,如果使用者在解析showMessage()函數之前就單擊了按鈕,這樣就會引發錯誤。為此,很多HTML事件處理函數都會封閉在 try -catch 塊中,這樣錯誤就不會暴露出來了,如下:
<input type="button" value="click me" onclick="try {showMessage()} catch(e) {}" />
2. HTML代碼與javascript代碼緊密耦合,如果要更新事件處理函數,就需要更新更新兩處位置。由於存在這兩個問題,我們在實際的工作中一般比較少用這種事件處理方式。
var btn = document.getElementById("myBtn");btn.onclick = function() {alert("clicked!");}
將一個函數賦值給一個事件處理常式的屬性,由於該方法至今的所有現在瀏覽器都支援,具有使用簡單,跨瀏覽器的優勢!使用DOM0級方法指定的事件處理常式被認為是元素的方法,這個時候事件都是在元素的範圍中啟動並執行,也就是說程式中的this引用當前的元素。
也可以刪除通過DOM0級方法指定的事件處理常式,如下:
btn.onclick = null;
DOM2級事件定義了兩個方法:addEventListener()、removeEventListener()
要在按鈕上為click添加事件處理常式,可以使用如下代碼:
var btn = document.getElementById("myBtn");btn.addEventListener("click", function() {alert(this.id);}, false);
因為第三個參數為false,所以事件會在冒泡階段觸發。使用DOM2級事處理常式的好處是可以添加多個事件處理常式。
同樣我們可以通過removeEventListener()來移除事件處理常式,如下:
var btn = document.getElementById("myBtn");btn.removeEventListener("click", function() {alert(this.id);}, false);
IE中實現了與DOM類似的兩個方法,attachEvent, deatachEvent(),如下代碼所示:
var btn = document.getElementById("myBtn");btn.attachEvent("click", function() {alert(this.id);});var btn = document.getElementById("myBtn");btn.detachEvent("click", function() {alert(this.id);});
由於DOM2級事件處理常式與IE中的事件處理常式不同,我們可能利用能力檢測統一事件處理常式,如下代碼所示:
var eventUtil = {addListener: function(element, type, hander) {if (element.addEventListener) {element.addEventListener(type, hander, false);} else if (element.attachEvent) {element.attachEvent('on' + type, hander);} else {element['on' + type] = hander;}},removeListener: function(element, type, hander) {if (element.removeEventListener) {element.removeEventListener(type, hander, false);} else if (element.deattachEvent) {element.detachEvent(type, hander);} else {element['on' + type] = null;}},};
相容DOM的瀏覽器會有一個event對象傳入到事件處理常式中,無論指定的事件處理常式時使用何方法,都會傳入event對象,我們常用的event對象的屬性及方法有:
1. currentTarget: 其事件處理常式當前正在處理事件的那個元素;
2. target: 事件的目標;
3. preventDefault(): 取消事件的預設行為;
4. stopPropagation(): 取消事件進一步捕獲劃冒泡。
與DOM中的事件對象一樣,IE中的事件對象同樣有以上屬性或方法,但是實現起來有些不一樣,以下是他們間的對應關係:
1. srcElement <=> target;
2. returnValue = false <=> preventDefault();
3. cancelBubble = true <=> stopPropagation();
由於DOM中的事件對象與IE中存在差異,我們同樣可以利用能力檢測的方法來統一事件對象中常用的屬性和方法(eventUtil.js):
var eventUtil = {addListener: function(element, type, hander) {if (element.addEventListener) {element.addEventListener(type, hander, false);} else if (element.attachEvent) {element.attachEvent('on' + type, hander);} else {element['on' + type] = hander;}},getEvent: function(event) {return event || window.event;//return event ? event : window.event;},getTarget: function(event) {return event.target || event.srcElement;},preventDefault: function(event) {if (event.preventDefault) {event.preventDefault();} else {event.returnValue = false;}},removeListener: function(element, type, hander) {if (element.removeEventListener) {element.removeEventListener(type, hander, false);} else if (element.deattachEvent) {element.detachEvent(type, hander);} else {element['on' + type] = null;}},stopPropagation: function(event) {if (event.stopPropagation) {event.stopPropagation();} else {event.cancelBubble = true;}}};
最後我們能過一個簡單的樣本來示範如何使用自訂的eventUtil對象,完整範例程式碼如下:
<html><head><title>event util test</title><script type="text/javascript" src="eventUtil.js"></script></head><body><a href="http://www.baidu.com">baidu</a><script type="text/javascript">(function() {var btn = document.getElementById("btn");var link = document.getElementsByTagName("a")[0];eventUtil.addListener(link, "click", function(event) {alert("prevent default event");var event = eventUtil.getEvent(event);eventUtil.preventDefault(event);});eventUtil.addListener(btn, "click", function(event) {var event = eventUtil.getEvent(event);var target = eventUtil.getTarget(event);alert(event.type);alert(target);eventUtil.stopPropagation(event);});eventUtil.addListener(document.body, "click", function() {alert("click body");});})();</script></body></html>