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