JavaScript与HTML之间的交互是通过事件实现的。可以使用侦听器来预订事件,以便事件发生时执行相应的代码。这种在传统软件工程中被称为观察员模式的模型。
事件流
事件流描述的是从页面中接收事件的顺序
事件冒泡
即事件开始时由最具体的节点接收,然后逐级向上传播到较为不具体的节点。
时间捕获
DOM事件流
- 事件捕获阶段
- 处于目标阶段
- 事件冒泡阶段
事件处理程序
事件就是用户或浏览器自身执行的某种动作。诸如click、load、mouseover,都是事件的名字。而响应某个事件的函数就叫做事件处理程序(或事件侦听器)。事件处理程序的名字以“on”开头。
<input type="button" value="Click Me" onclick="alert(event.type)">
//输出"click"。函数有一个局部变量event。
<input type="button" value="Click Me" onclick="alert(this.value)">
//输出"Click Me"。this值等于事件的目标元素。
<input type="button" value="Click Me" onclick="alert(value)">
//输出"Click Me"。在函数内部,可以像访问局部变量一样访问document及该元素本身的成员。
<form method="post">
<input type="text" name="username" value="" >
<input type="button" value="Echo Username" onclick="alert(username.value)">
</form>
//当输入元素是一个表单输入元素,则作用域中还会包含表单访问元素(父元素)的入口。
注意:在HTML指定事件处理程序的两个缺点:1.时差问题,事件触发时程序可能还没解析。解决:把HTML处理程序封装在一个try-catch块中,以便错误不会浮出水面。2这样扩展 事件处理程序的作用域在不同的浏览器中会有不同的结果,不同JavaScript引擎遵循的标识符解析规则略有差异。最后,通过HTML指定事件处理程序的最后一个缺点就是HTML与JavaScript代码的紧密耦合。
DOM0级事件处理程序
使用JavaScript指定事件处理程序,首先必须取得一个要操作的对象的引用。每个元素(包括window和document)都有自己的事件处理程序属性,将这个属性的值设置为一个函数,就可以指定事件处理程序。
var btn = document.getElementById("myBtn");
btn.onclick = function(){
alert(this.id);
};
使用DOM0级方法指定的事件处理程序被认为是元素的方法,在元素的作用域中运行,会在事件流的冒泡阶段被处理。也可以删除DOM0级方法指定的事件处理程序。
var removeBtn = document.getElementById("myRemoveBtn");
removeBtn.onclick = function(){
btn.onclick = null;
};
DOM2级事件处理程序
最后一个布尔值参数如果是true,表示在捕获阶段调用事件处理程序;如果是false(推荐),表示在冒泡阶段调用事件处理程序。程序也是在元素的作用域中运行。
使用DOM2级方法添加事件处理程序的主要好处是可以添加多个事件处理程序。
只能通过removeEventListener()来移除,参数和addEventListener()方法相同,也意味着通过addEventListener()添加的匿名函数将无法移除.
var btn = document.getElementById("myBtn");
btn.addEventListener("click", function(){
alert(this.id);
}, false);
btn.addEventListener("click", function(){
alert("Hello world!");
}, false);
IE事件处理程序
也是两个方法:attachEvent()和detachEvent(),只要两个参数。由于IE8及更早版本只支持事件冒泡。所以通过这种方式添加的事件处理程序只会被添加到冒泡阶段。
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(){
alert("Clicked");
});
//注意这种方式的第一个参数是“onclick”。
和DOM0级的方法的主要区别在于事件处理程序的作用域。事件处理程序是在全局作用域中运行,因此this等于window:
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(){
alert(this === window); //true
});
注意:虽然attachEvent()方法也可以用来为一个元素添加多个事件处理程序。但是程序的执行顺序和他们添加的顺序相反。
跨浏览器的事件处理程序
var EventUtil = {
addHandler: function(element, type, handler){
if (element.addEventListener){
element.addEventListener(type, handler, false);
} else if (element.attachEvent){
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler;
}
},
removeHandler: function(element, type, handler){
if (element.removeEventListener){
element.removeEventListener(type, handler, false);
} else if (element.detachEvent){
element.detachEvent("on" + type, handler);
} else {
element["on" + type] = null;
}
}
};
事件对象
在触发DOM上的某个事件时,会产生一个事件对象event,这个对象包含着所有与事件有关的信息。导致事件的元素、事件的类型、与特定事件相关信息。如,鼠标操作导致的event对象会包含鼠标位置信息。键盘操作导致的event对象会包含按下的键有关信息。所有浏览器都支持event对象,但支持方式不同。
DOM中的事件对象
var link = document.getElementById("myLink");
link.onclick = function(event){
event.preventDefault();
};
//这样就阻止了元素的click事件的默认行为。这种方法的前提是只对cancelable属性设置为true的事件有效。
var btn = document.getElementById("myBtn");
btn.onclick = function(event){
alert("Clicked");
event.stopPropagation();
};
document.body.onclick = function(event){
alert("Body clicked");
};
//stopPropagation()会立即停止事件在DOM层次中的传播,在此例不会传播到document上。
IE中的事件对象
在使用DOM0级方法添加事件处理程序时,event对象作为window对象的一个属性存在。
在使用attachEvent()方法添加事件处理程序时,那么就会有一个event对象作为参数被传入事件处理程序中。
var btn = document.getElementById("myBtn");
btn.onclick = function(){
alert(event.type); //"click"
};
//event也可以通过window对象访问