最近在看《javascript 高级程序》一书,写自己的一些小心得体会,希望得到牛人们的指点,讨论。

步入今天的正题,javascript事件处理函数,我们知道,javascript与HTML之间的交互是通过事件来实现的,事件就是用户或浏览器自身执行的某种动作,比如click、mounseover、load……,而响应事件的函数就叫做事件处理函数(或事件侦听器)。

  • HTML代码中的事件处理程序:
<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代码紧密耦合,如果要更新事件处理函数,就需要更新更新两处位置。由于存在这两个问题,我们在实际的工作中一般比较少用这种事件处理方式。

  • DOM0级事件处理程序:
		var btn = document.getElementById("myBtn");
		btn.onclick = function() {
			alert("clicked!");
		}

将一个函数赋值给一个事件处理程序的属性,由于该方法至今的所有现在浏览器都支持,具有使用简单,跨浏览器的优势!使用DOM0级方法指定的事件处理程序被认为是元素的方法,这个时候事件都是在元素的作用域中运行的,也就是说程序中的this引用当前的元素。

也可以删除通过DOM0级方法指定的事件处理程序,如下:

btn.onclick = null;
  • DOM2级事件处理程序:

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事件处理程序

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中的事件对象:

兼容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):

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>

作者: 张臣 发表于 2011-08-01 21:56 原文链接

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架
新浪微博粉丝精灵,刷粉丝、刷评论、刷转发、企业商家微博营销必备工具"