标签:
目录
事件,由WEB页面中发生的一些特定行为触发。比如在某个页面元素上按下鼠标左键,按下键盘某个按键,某对象获得或丢失焦点时均会触发对应的事件。JavaScript和HTML的交互就是通过事件来实现的。我们使用事件侦听器对事件进行“注册”,事件发生时便执行相应的代码。
DOM0级事件处理程序以其简单、跨浏览器支持的特点,至今仍为所有浏览器支持。
通过DOM0级方法指定事件处理程序方法很简单,就是直接将一个函数赋值给一个事件处理程序属性。
有关事件处理程序属性,有以下几点需要说明:
1、事件处理程序属性全部小写,以”on”开头,后面跟事件类型:
onclick //单击鼠标
onload //图像或页面载入完成
onmouseover //将鼠标移动到某元素上面
onmousemove //移动鼠标
onfocus //对象获得焦点
2、每个元素如img、a、input、form包括window和document都拥有自己的事件处理程序属性。如:
document.getElementById("btn1").onclick //btn1上单击鼠标
document.getElementById("img1").onmouseover //鼠标移动到img1
document.getElementById("img1").onmerror //img1图像无法载入
接下来,给事件处理程序属性赋值即可完成事件处理程序方法的指定。例如,当鼠标移动到”img1”上时,弹出对话框”This is a nice pic!”:
var pic1 = document.getElementById("img1");
pic1.onmouseover = function() {
alert("This is a nice pic!");
};
特别注意:如果以上代码处于文档的底部,在页面刚刚加载时,我们将鼠标移动到img1上面。有可能由于代码尚未执行,不会弹出我们设定的对话框!
通过DOM0级方法指定的事件处理程序,属于元素方法
。因此,我们在事件处理程序中的this引用的是该元素!通过以下例子来说明:
<input id="btn1" type="button" value="Click Me" />
...//省略
<script type="text/javascript">
<!--
var btn1 = document.getElementById("btn1");
btn1.onclick = function() {
alert(this.id + "\n" + this.type + "\n" + this.value);
};
-->
</script>
要删除事件处理程序,只需要将对应的事件处理程序属性设置为null即可:
pic1.onmouseover = null;
当我们在Web页面单击某一个元素的时候,比如某个div元素。显然我们单击的不仅仅是这一个div元素,一同被单击的还有div的容器body、body的父元素html还有外层的document。事件在这些嵌套的元素之间的传播称为事件流。
IE的事件流称为事件冒泡,事件从最具体的元素开始,逐级向上传播。我们使用DOM0添加的事件处理程序就是在事件冒泡阶段被处理的。例如:
<html>
<head>
<script type="text/javascript">
window.onload = bubblingHandle;
function bubblingHandle() {
//内层div处理程序
document.getElementById("inner").onmousedown = function() {
alert("inner div");
}
//外层div处理程序
document.getElementById("outer").onmousedown = function() {
alert("outerDiv");
}
document.onmousedown = function() {
alert("document");
}
}
-->
</script>
</head>
<body>
<div id="outer" style="background-color:black; padding: 15px;">
<div id="inner" style="background-color:white; padding: 5px;"></div>
</div>
</body>
</html>
当点击内层的白色div时,会依次显示:
inner div
outer div
document
事件传播示意图如下:
网景提出的事件流称为事件捕获,其与IE几乎相反。事件首先由最不具体的元素接收,然后逐级向具体节点传播。
目前,几乎所有的浏览器都支持DOM0事件模型,但鼓励开发人员使用新的DOM2模型。DOM2模型与DOM0有两个显著区别:
DOM2定义了2个方法:
addEventListener() //指定事件处理程序
removeEventListener() //删除事件处理程序
所有DOM节点有包含这两个方法,这两个方法用法如下,它们都接收3个参数,第1个为要处理事件名(不含on),第2个事件处理函数,第3个布尔变量:
例如我们为按钮btn1的单击事件添加2个事件处理程序,事件处理程序在事件冒泡阶段被处理:
<input id="btn1" type="button" value="Click Me" />
...
<script type="text/javascript">
<!--
var btn1 = document.getElementById("btn1");
var handle1 = function() {
alert("handle1!");
}
var handle2 = function() {
alert("handle2!");
}
btn1.addEventListener("click", handle1, false);
btn1.addEventListener("click", handle2, false);
-->
</script>
当单击btn1按钮时,会依次弹出对话框:
handle1!
handle2!
我们可以用removeEventListener()方法来删除我们刚才指定的事件处理程序,注意参数要保持一致:
btn1.removeEventListener("click", handle2, false);
此时单击btn1按钮,只会显示handle1!。
要特别注意的是,如果我们使用匿名函数指定事件处理程序,便无法使用removeEventListener()方法删除事件处理程序:
btn1.addEventListener("click", function(){
alert("click!");
}, false);
btn1.removeEventListener("click", function(){
alert("click!");
}, false); //无法取消!
这样是无法取消以上指定的事件处理程序的!
另外,强调一点,以上两个函数的第一个参数(要处理的事件名)是没有on前缀的。这一点和IE不同,后面会说明。
DOM2事件处理程序和DOM0相同,它们的this都在其依附的元素作用域中运行。this的指代参考DOM0的示例。这里之所以要特别指出DOM2的this,是为了和IE事件处理程序进行区分。
IE并没有提供对W3C事件模型的支持,其实现了2个和DOM2模型类似的方法:
attachEvent()
detachEvent()
这两个方法只接收2个参数:事件名称以及事件处理函数。由于IE只支持事件冒泡,这两个方法添加的事件处理程序会在事件冒泡阶段被执行。
和DOM2不同的是:
例如:
<input id="btn1" type="button" value="Click Me" />
...
<script type="text/javascript">
<!--
var btn1 = document.getElementById("btn1");
var handle1 = function() {
alert("handle1!" + "\n" + (this === window));
};
var handle2 = function() {
alert("handle2!"+ "\n" + (this === window));
};
btn1.attachEvent("onclick", handle1);
btn1.attachEvent("onclick", handle2);
-->
</script>
执行结果:
handle2!
true
handle1!
true
虽然可以使用屏蔽浏览器差异的JS库,实际上,我们自己编写一个跨浏览器兼容的事件处理代码并不是一件困难的事情,同时更有利于我们对原生JavaScript的学习理解。我们使用一个习惯上称为EventUtil的对象来进行跨浏览器事件处理:
var EventUtil = {
addEventHandler : function(element, eventType, handler) {
if(element.addEventListener){
element.addEventListener(eventType, handler, flase);
} else if(element.attachEvent) {
element.attachEvent("on" + eventType, handler);
} else {
element["on" + eventType] = handler;
}
},
removeEventHandler : function(element, eventType, handler) {
if(element.aremoveEventListener){
element.addEventListener(eventType, handler, flase);
} else if(element.detachEvent) {
element.attachEvent("on" + eventType, handler);
} else {
element["on" + eventType] = null;
}
}
}
以上代码使用浏览器能力检测,首先检测是否支持addEventListener或removeEventListener方法,如果支持则使用该方法;如果不支持该方法,检测是否支持IE的attachEvent或detachEvent方法,若支持则使用该方法;如果对以上2种方法都不支持,则使用DOM0级方法。要注意,DOM0级对每个事件只能指定一个事件处理程序。
以上对象使用示例如下:
var btn1 = document.getElementById("btn1");
var handle1 = function() {
alert("handle1!" + "\n" + (this === window));
};
var handle2 = function() {
alert("handle2!"+ "\n" + (this === window));
};
EventUtil.addEventHandler(btn1, "click", handler1);
EventUtil.addEventHandler(btn1, "click", handler2);
EventUtil.removeEventHandler(btn1, "click", handler2);
在触发某个事件时,会产生一个event对象。该对象中包含与事件有关的信息。例如触发事件的元素、事件的类型、与特定事件相关的如鼠标位置信息等。
不论使用DOM0级还是DOM2级方法指定事件处理程序,事件触发时都会自动将一个event对象传入事件处理程序,例如:
var btn1 = document.getElementById("btn1");
btn1.onmouseover = function(evnt) {
alert(evnt.type);
}
var handle = function(evnt) {
alert(evnt.type);
};
btn1.addEventListener("click", handle, false);
当鼠标移动到btn1上时,会弹出:
当点击btn1时,会弹出:
以上是一个简单的event对象的示例。event对象中的type属性是一个只读字符串属性,其中包含着事件的类型。例如我们上例中的click和onmouseover。event对象中包含有大量的有关事件的信息和方法(例如event.stopPropagation()方法可用于停止事件在捕获或者冒泡阶段的继续传播,preventDefault()方法会取消阻止事件的行)在此就不一一列举了。
我们这里只需要知道,浏览器会将一个event对象传入到事件处理程序中,关于该对象的具体用法可以参考其他文献。
在IE中,当使用DOM0级指定事件处理程序时,event对象被认为是window的一个属性,例如获取鼠标点击坐标的代码:
var mouseLoc = function() {
var loc = "x: " + window.event.screenX + "\n" +
"y: " + window.event.screenY;
alert(loc);
};
当使用attachEvent()方法指定事件处理程序时,event对象会被作为参数传入事件处理程序,我们将以上的代码重写:
var mouseLoc = function(event) {
var loc = "x: " + event.screenX + "\n" +
"y: " + event.screenY;
alert(loc);
};
btn1.attachEvent("onclick", mouseLoc);
解决跨浏览器问题的思路是一贯的,我们可以对浏览器进行能力检测,这里我们对上面的EventUtil对象进行扩展,对我们学习原生JS,这是一个很漂亮的对象:
var EventUtil = {
addEventHandler : function(element, eventType, handler) {
if(element.addEventListener){
element.addEventListener(eventType, handler, flase);
} else if(element.attachEvent) {
element.attachEvent("on" + eventType, handler);
} else {
element["on" + eventType] = handler;
}
},
removeEventHandler : function(element, eventType, handler) {
if(element.aremoveEventListener){
element.addEventListener(eventType, handler, flase);
} else if(element.detachEvent) {
element.attachEvent("on" + eventType, handler);
} else {
element["on" + eventType] = null;
}
},
getEvent: function (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;
}
},
stopPropagation: function (event) {
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubbles = true;
}
},
getRelatedTarget: function (event) {
if (event.relatedTarger) {
return event.relatedTarget;
} else if (event.toElement) {
return event.toElement;
} else if (event.fromElement) {
return event.fromElement;
} else { return null; }
}
}
标签:
原文地址:http://blog.csdn.net/a153375250/article/details/51132463