JavaScript 与 HTML 之间的交互是通过事件实现的。事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间。可以使用侦听器(或处理程序)来预订事件,以便事件发生时执行相应的代码。这种在传统软件工程中被称为 观察员模式 的模型,支持页面的行为(JavaScript 代码)与页面的外观(HTML 和 CSS 代码)之间的松散耦合。
一、事件流
事件流 描述的是 从页面中接收事件的顺序。
- IE 的事件流是 事件冒泡流,
- 而 Netscape Communicator 的事件流是 事件捕获流。
1. 事件冒泡
IE 的事件流叫做 事件冒泡(event bubbling),即 事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。以下面的 HTML 页面为例:
<!DOCTYPE html>
<html>
<head>
<title>Event Bubbling Example</title>
</head>
<body>
<div id="myDiv">Click Me</div>
</body>
</html>
如果你单击了页面中的 <div>
元素,那么这个 click
事件会按照如下顺序传播:<div>
、<body>
、<html>
、document
也就是说,click
事件首先在 <div>
元素上发生,而这个元素就是我们单击的元素。然后,click
事件沿 DOM
树向上传播,在每一级节点上都会发生,直至传播到 document
对象。图 中展示了事件冒泡的过程。
![](https://img.haomeiwen.com/i4840088/4067553c4053b589.png)
所有现代浏览器都支持事件冒泡,但在具体实现上还是有一些差别。
- IE5.5 及更早版本中的事件冒泡会跳过
<html>
元素(从<body>
直接跳到document
)。 - IE9、Firefox、Chrome 和 Safari 则将事件一直冒泡到
window
对象。
2. 事件捕获
Netscape Communicator 团队提出的另一种事件流叫做 事件捕获(event capturing)。事件捕获的思想是 不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。
事件捕获的用意在于在事件到达预定目标之前捕获它。如果仍以前面的 HTML 页面作为演示事件捕获的例子,那么单击 <div>
元素就会以下列顺序触发 click
事件:document
、<html>
、<body>
、<div>
在事件捕获过程中,document
对象首先接收到 click
事件,然后事件沿 DOM 树依次向下,一直传播到事件的实际目标,即 <div>
元素。图展示了事件捕获的过程。
![](https://img.haomeiwen.com/i4840088/c3832e61c5150959.png)
在 DOM 事件流中,实际的目标(<div>
元素)在捕获阶段不会接收到事件。这意味着在捕获阶段,事件从 document
到 <html>
再到 <body>
后就停止了。下一个阶段是“处于目标”阶段,于是事件在 <div>
上发生,并在事件处理(后面将会讨论这个概念)中被看成冒泡阶段的一部分。然后,冒泡阶段发生,事件又传播回文档。
多数支持 DOM 事件流的浏览器都实现了一种特定的行为;即使 “DOM2 级事件” 规范明确要求捕获阶段不会涉及事件目标,但 IE9、Safari、Chrome、Firefox 和 Opera 9.5 及更高版本都会在捕获阶段触发事件对象上的事件。结果,就是有两个机会在目标对象上面操作事件。
二、 事件处理程序
事件就是用户或浏览器自身执行的某种动作。诸如 click
、load
和 mouseover
,都是事件的名字。
而响应某个事件的函数就叫做事件处理程序(或事件侦听器)。事件处理程序的名字以 on
开头,因此 click
事件的事件处理程序就是 onclick
,load
事件的事件处理程序就是 onload。为事件指定处理程序的方式有好几种。
1. HTML事件处理程序
某个元素支持的每种事件,都可以使用一个与相应事件处理程序同名的 HTML 特性来指定。这个特性的值应该是能够执行的 JavaScript 代码。例如,要在按钮被单击时执行一些 JavaScript,可以像下面这样编写代码:
<input type="button" value="Click Me" onclick="console.log('Clicked')" />
在 HTML 中定义的事件处理程序可以包含要执行的具体动作,也可以调用在页面其他地方定义的脚本,如下面的例子所示:
<script type="text/javascript">
function showMessage(){
console.log("Hello world!");
}
</script>
<input type="button" value="Click Me" onclick="showMessage()" />
在这个例子中,单击按钮就会调用 showMessage()
函数。这个函数是在一个独立的 <script>
元素中定义的,当然也可以被包含在一个外部文件中。事件处理程序中的代码在执行时,有权访问全局作用域中的任何代码。
这样指定事件处理程序具有一些独到之处。首先,这样会创建一个封装着元素属性值的函数。这个函数中有一个局部变量 event
,也就是事件对象。
2. DOM0 级事件处理程序
通过 JavaScript 指定事件处理程序的传统方式,就是 将一个函数赋值给一个事件处理程序属性。这种为事件处理程序赋值的方法是在第四代 Web 浏览器中出现的,而且至今仍然为所有现代浏览器所支持。原因一是简单,二是具有跨浏览器的优势。要使用 JavaScript 指定事件处理程序,首先必须取得一个要操作的对象的引用。
每个元素(包括 window
和 document
)都有自己的事件处理程序属性,这些属性通常全部小写,例如 onclick
。将这种属性的值设置为一个函数,就可以指定事件处理程序,如下所示:
var btn = document.getElementById("myBtn");
btn.onclick = function(){
console.log("Clicked");
};
在此,我们通过文档对象取得了一个按钮的引用,然后为它指定了 onclick
事件处理程序。但要注意,在这些代码运行以前不会指定事件处理程序,因此如果这些代码在页面中位于按钮后面,就有可能在一段时间内怎么单击都没有反应。
使用 DOM0 级方法指定的事件处理程序被认为是元素的方法。因此,这时候的事件处理程序是在元素的作用域中运行;换句话说,程序中的 this 引用当前元素。来看一个例子。
var btn = document.getElementById("myBtn");
btn.onclick = function(){
console.log(this.id); // "myBtn"
};
单击按钮显示的是元素的 ID,这个 ID 是通过 this.id
取得的。不仅仅是 ID,实际上可以在事件处理程序中通过 this
访问元素的任何属性和方法。以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理。
也可以删除通过 DOM0 级方法指定的事件处理程序,只要像下面这样将事件处理程序属性的值设置为 null
即可:
btn.onclick = null; // 删除事件处理程序
将事件处理程序设置为 null
之后,再单击按钮将不会有任何动作发生。
3. DOM2 级事件处理程序
“DOM2级事件”定义了两个方法,用于处理指定和删除事件处理程序的操作:addEventListener()
和removeEventListener()
。
所有 DOM 节点中都包含这两个方法,并且它们都接受 3 个参数:要处理的事件名、作为事件处理程序的函数 和 一个布尔值。
最后这个布尔值参数如果是 true
,表示在捕获阶段调用事件处理程序;如果是 false
,表示在冒泡阶段调用事件处理程序。
要在按钮上为 click
事件添加事件处理程序,可以使用下列代码:
var btn = document.getElementById("myBtn");
btn.addEventListener("click", function(){
console.log(this.id);
}, false);
上面的代码为一个按钮添加了 onclick
事件处理程序,而且该事件会在冒泡阶段被触发(因为最后一个参数是 false
)。与 DOM0 级方法一样,这里添加的事件处理程序也是在其依附的元素的作用域中运行。使用 DOM2 级方法添加事件处理程序的主要好处是可以添加多个事件处理程序。来看下面的例子。
var btn = document.getElementById("myBtn");
btn.addEventListener("click", function(){
console.log(this.id);
}, false);
btn.addEventListener("click", function(){
console.log("Hello world!");
}, false);
这里为按钮添加了两个事件处理程序。这两个事件处理程序会按照添加它们的顺序触发,因此首先会显示元素的 ID
,其次会显示 "Hello world!"
消息。
通过 addEventListener()
添加的事件处理程序只能使用 removeEventListener()
来移除;移除时传入的参数与添加处理程序时使用的参数相同。这也意味着通过 addEventListener()
添加的匿名函数将无法移除,如下面的例子所示。
var btn = document.getElementById("myBtn");
btn.addEventListener("click", function(){
console.log(this.id);
}, false);
//这里省略了其他代码
btn.removeEventListener("click", function(){ // 没有用!
console.log(this.id);
}, false);
在这个例子中,我们使用 addEventListener()
添加了一个事件处理程序。虽然调用 removeEventListener()
时看似使用了相同的参数,但实际上,第二个参数与传入 addEventListener()
中的那一个是完全不同的函数。而传入 removeEventListener()
中的事件处理程序函数必须与传入 addEventListener()
中的相同,如下面的例子所示。
var btn = document.getElementById("myBtn");
var handler = function(){
alert(this.id);
};
btn.addEventListener("click", handler, false);
//这里省略了其他代码
btn.removeEventListener("click", handler, false); //有效!
重写后的这个例子没有问题,是因为在 addEventListener()和 removeEventListener()中使用了相同的函数。
大多数情况下,都是将事件处理程序添加到事件流的冒泡阶段,这样可以最大限度地兼容各种浏览器。最好只在需要在事件到达目标之前截获它的时候将事件处理程序添加到捕获阶段。如果不是特别需要,我们不建议在事件捕获阶段注册事件处理程序。
4. IE事件处理程序
IE 实现了与 DOM 中类似的两个方法:attachEvent()
和 detachEvent()
。这两个方法接受相同的两个参数:事件处理程序名称与事件处理程序函数。由于 IE8 及更早版本只支持事件冒泡,所以通过 attachEvent()
添加的事件处理程序都会被添加到冒泡阶段。
要使用 attachEvent()
为按钮添加一个事件处理程序,可以使用以下代码。
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(){
alert("Clicked");
});
注意,attachEvent()的第一个参数是"onclick",而非 DOM 的 addEventListener()方法中的"click"。
在 IE 中使用 attachEvent()与使用 DOM0 级方法的主要区别在于事件处理程序的作用域。在使用 DOM0 级方法的情况下,事件处理程序会在其所属元素的作用域内运行;在使用 attachEvent()方法的情况下,事件处理程序会在全局作用域中运行,因此 this 等于 window。来看下面的例子。
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(){
alert(this === window); //true
});
在编写跨浏览器的代码时,牢记这一区别非常重要。
与 addEventListener()类似,attachEvent()方法也可以用来为一个元素添加多个事件处理程序。来看下面的例子。
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(){
alert("Clicked");
});
btn.attachEvent("onclick", function(){
alert("Hello world!");
});
这里调用了两次 attachEvent(),为同一个按钮添加了两个不同的事件处理程序。不过,与 DOM方法不同的是,这些事件处理程序不是以添加它们的顺序执行,而是以相反的顺序被触发。单击这个例子中的按钮,首先看到的是"Hello world!",然后才是"Clicked"。
使用 attachEvent()添加的事件可以通过 detachEvent()来移除,条件是必须提供相同的参数。与 DOM 方法一样,这也意味着添加的匿名函数将不能被移除。不过,只要能够将对相同函数的引用传给 detachEvent(),就可以移除相应的事件处理程序。例如:
var btn = document.getElementById("myBtn");
var handler = function(){
alert("Clicked");
};
btn.attachEvent("onclick", handler);
//这里省略了其他代码
btn.detachEvent("onclick", handler);
这个例子将保存在变量 handler 中的函数作为事件处理程序。因此,后面的 detachEvent()可以使用相同的函数来移除事件处理程序。
5. 跨浏览器的事件处理程序
为了以跨浏览器的方式处理事件,不少开发人员会使用能够隔离浏览器差异的 JavaScript 库,还有一些开发人员会自己开发最合适的事件处理的方法。自己编写代码其实也不难,只要恰当地使用能力检测即可。要保证处理事件的代码能在大多数浏览器下一致地运行,只需关注冒泡阶段。
第一个要创建的方法是 addHandler(),它的职责是视情况分别使用 DOM0 级方法、DOM2 级方法或 IE 方法来添加事件。这个方法属于一个名叫 EventUtil 的对象,本书将使用这个对象来处理浏览器间的差异。addHandler()方法接受 3 个参数:要操作的元素、事件名称和事件处理程序函数。
与 addHandler()对应的方法是 removeHandler(),它也接受相同的参数。这个方法的职责是移除之前添加的事件处理程序——无论该事件处理程序是采取什么方式添加到元素中的,如果其他方法无效,默认采用 DOM0 级方法。
EventUtil 的用法如下所示。
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;
}
}
};
这两个方法首先都会检测传入的元素中是否存在 DOM2 级方法。如果存在 DOM2 级方法,则使用该方法:传入事件类型、事件处理程序函数和第三个参数 false(表示冒泡阶段)。如果存在的是 IE 的方法,则采取第二种方案。注意,为了在 IE8 及更早版本中运行,此时的事件类型必须加上"on"前缀。最后一种可能就是使用 DOM0 级方法(在现代浏览器中,应该不会执行这里的代码)。此时,我们使用的是方括号语法来将属性名指定为事件处理程序,或者将属性设置为 null。
可以像下面这样使用 EventUtil 对象:
var btn = document.getElementById("myBtn");
var handler = function(){
alert("Clicked");
};
EventUtil.addHandler(btn, "click", handler);
//这里省略了其他代码
EventUtil.removeHandler(btn, "click", handler);
addHandler()和 removeHandler()没有考虑到所有的浏览器问题,例如在 IE 中的作用域问题。不过,使用它们添加和移除事件处理程序还是足够了。此外还要注意,DOM0 级对每个事件只支持一个事件处理程序。好在,只支持 DOM0 级的浏览器已经没有那么多了,因此这对你而言应该不是什么问题。
三、事件对象
在触发 DOM 上的某个事件时,会产生一个事件对象 event,这个对象中包含着所有与事件有关的信息。包括导致事件的元素、事件的类型以及其他与特定事件相关的信息。例如,鼠标操作导致的事件对象中,会包含鼠标位置的信息,而键盘操作导致的事件对象中,会包含与按下的键有关的信息。所有浏览器都支持 event 对象,但支持方式不同。
1. DOM中的事件对象
兼容 DOM 的浏览器会将一个 event 对象传入到事件处理程序中。无论指定事件处理程序时使用什么方法(DOM0 级或 DOM2 级),都会传入 event 对象。来看下面的例子。
var btn = document.getElementById("myBtn");
btn.onclick = function(event){
alert(event.type); //"click"
};
btn.addEventListener("click", function(event){
alert(event.type); //"click"
}, false);
这个例子中的两个事件处理程序都会弹出一个警告框,显示由 event.type
属性表示的事件类型。这个属性始终都会包含被触发的事件类型,例如 click
(与传入 addEventListener()
和 removeEventListener()
中的事件类型一致)。
在通过 HTML 特性指定事件处理程序时,变量 event 中保存着 event 对象。请看下面的例子。
<input type="button" value="Click Me" onclick="alert(event.type)"/>
以这种方式提供 event
对象,可以让 HTML 特性事件处理程序与 JavaScript 函数执行相同的操作。
event
对象包含与创建它的特定事件有关的属性和方法。触发的事件类型不一样,可用的属性和方法也不一样。不过,所有事件都会有下表列出的成员。
属性/方法 | 类 型 | 读/写 | 说 明 |
---|---|---|---|
bubbles | Boolean | 只读 | 表明事件是否冒泡 |
cancelable | Boolean | 只读 | 表明是否可以取消事件的默认行为 |
currentTarget | Element | 只读 | 其事件处理程序当前正在处理事件的那个元素 |
defaultPrevented | Boolean | 只读 | 为 true 表示已经调用了 preventDefault() (DOM3级事件中新增) |
detail | Integer | 只读 | 与事件相关的细节信息 |
eventPhase | Integer | 只读 | 调用事件处理程序的阶段:1表示捕获阶段,2表示“处于目标”,3表示冒泡阶段 |
preventDefault() | Function | 只读 | 取消事件的默认行为。如果cancelable是true,则可以使用这个方法 |
stopImmediatePropagation() | Function | 只读 | 取消事件的进一步捕获或冒泡,同时阻止任何事件处理程序被调用(DOM3级事件中新增) |
stopPropagation() | Function | 只读 | 取消事件的进一步捕获或冒泡。如果bubbles为true,则可以使用这个方法 |
target | Element | 只读 | 事件的目标 |
trusted | Boolean | 只读 | 为true表示事件是浏览器生成的。为false表示事件是由开发人员通过 JavaScript 创建的(DOM3级事件中新增) |
type | String | 只读 | 被触发的事件的类型 |
view | AbstractView | 只读 | 与事件关联的抽象视图。等同于发生事件的window对象 |
在事件处理程序内部,对象 this 始终等于 currentTarget 的值,而 target 则只包含事件的实际目标。如果直接将事件处理程序指定给了目标元素,则 this、currentTarget 和 target 包含相同的值。来看下面的例子。
var btn = document.getElementById("myBtn");
btn.onclick = function(event){
alert(event.currentTarget === this); //true
alert(event.target === this); //true
};
这个例子检测了 currentTarget 和 target 与 this 的值。由于 click 事件的目标是按钮,因此这三个值是相等的。如果事件处理程序存在于按钮的父节点中(例如 document.body),那么这些值是不相同的。再看下面的例子。
document.body.onclick = function(event){
alert(event.currentTarget === document.body); //true
alert(this === document.body); //true
alert(event.target === document.getElementById("myBtn")); //true
};
当单击这个例子中的按钮时,this 和 currentTarget 都等于 document.body,因为事件处理程序是注册到这个元素上的。然而,target 元素却等于按钮元素,因为它是 click 事件真正的目标。由于按钮上并没有注册事件处理程序,结果 click 事件就冒泡到了 document.body,在那里事件才得到了处理。
在需要通过一个函数处理多个事件时,可以使用 type 属性。例如:
var btn = document.getElementById("myBtn");
var handler = function(event){
switch(event.type){
case "click":
alert("Clicked");
break;
case "mouseover":
event.target.style.backgroundColor = "red";
break;
case "mouseout":
event.target.style.backgroundColor = "";
break;
}
};
btn.onclick = handler;
btn.onmouseover = handler;
btn.onmouseout = handler;
这个例子定义了一个名为 handler 的函数,用于处理 3 种事件:click、mouseover 和 mouseout。当单击按钮时,会出现一个与前面例子中一样的警告框。当按钮移动到按钮上面时,背景颜色应该会变成红色,而当鼠标移动出按钮的范围时,背景颜色应该会恢复为默认值。这里通过检测 event.type属性,让函数能够确定发生了什么事件,并执行相应的操作。
要阻止特定事件的默认行为,可以使用 preventDefault()方法。例如,链接的默认行为就是在被单击时会导航到其 href 特性指定的 URL。如果你想阻止链接导航这一默认行为,那么通过链接的onclick 事件处理程序可以取消它,如下面的例子所示。
var link = document.getElementById("myLink");
link.onclick = function(event){
event.preventDefault();
};
只有 cancelable 属性设置为 true 的事件,才可以使用 preventDefault()来取消其默认行为。
另外,stopPropagation()方法用于立即停止事件在 DOM 层次中的传播,即取消进一步的事件捕获或冒泡。例如,直接添加到一个按钮的事件处理程序可以调用 stopPropagation(),从而避免触发注册在 document.body 上面的事件处理程序,如下面的例子所示。
var btn = document.getElementById("myBtn");
btn.onclick = function(event){
alert("Clicked");
event.stopPropagation();
};
document.body.onclick = function(event){
alert("Body clicked");
};
对于这个例子而言,如果不调用 stopPropagation(),就会在单击按钮时出现两个警告框。可是,由于 click 事件根本不会传播到 document.body,因此就不会触发注册在这个元素上的 onclick 事件处理程序。
事件对象的 eventPhase 属性,可以用来确定事件当前正位于事件流的哪个阶段。如果是在捕获阶段调用的事件处理程序,那么 eventPhase 等于 1;如果事件处理程序处于目标对象上,则 eventPhase等于 2;如果是在冒泡阶段调用的事件处理程序,eventPhase 等于 3。这里要注意的是,尽管“处于目标”发生在冒泡阶段,但 eventPhase 仍然一直等于 2。来看下面的例子。
var btn = document.getElementById("myBtn");
btn.onclick = function(event){
alert(event.eventPhase); //2
};
document.body.addEventListener("click", function(event){
alert(event.eventPhase); //1
}, true);
document.body.onclick = function(event){
alert(event.eventPhase); //3
};
当单击这个例子中的按钮时,首先执行的事件处理程序是在捕获阶段触发的添加到 document.body
中的那一个,结果会弹出一个警告框显示表示 eventPhase
的 1。接着,会触发在按钮上注册的事件处理程序,此时的 eventPhase
值为 2。最后一个被触发的事件处理程序,是在冒泡阶段执行的添加到 document.body
上的那一个,显示 eventPhase
的值为 3。而当 eventPhase
等于 2 时,this
、target
和 currentTarget
始终都是相等的。
2. IE中的事件对象
与访问 DOM 中的 event 对象不同,要访问 IE 中的 event 对象有几种不同的方式,取决于指定事件处理程序的方法。在使用 DOM0 级方法添加事件处理程序时,event 对象作为 window 对象的一个属性存在。来看下面的例子。
var btn = document.getElementById("myBtn");
btn.onclick = function(){
var event = window.event;
alert(event.type); //"click"
};
在此,我们通过 window.event 取得了 event 对象,并检测了被触发事件的类型(IE 中的 type属性与 DOM 中的 type 属性是相同的)。可是,如果事件处理程序是使用 attachEvent()添加的,那么就会有一个 event 对象作为参数被传入事件处理程序函数中,如下所示。
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(event){
alert(event.type); //"click"
});
在像这样使用 attachEvent()的情况下,也可以通过 window 对象来访问 event 对象,就像使用DOM0 级方法时一样。不过为方便起见,同一个对象也会作为参数传递。
如果是通过HTML特性指定的事件处理程序,那么还可以通过一个名叫event的变量来访问event对象(与 DOM 中的事件模型相同)。再看一个例子。
<input type="button" value="Click Me" onclick="alert(event.type)">
属性/方法 | 类 型 | 读/写 | 说 明 |
---|---|---|---|
cancelBubble | Boolean | 读/写 | 默认值为false,但将其设置为true就可以取消事件冒泡(与DOM中的stopPropagation()方法的作用相同) |
returnValue | Boolean | 读/写 | 默认值为true,但将其设置为false就可以取消事件的默认行为(与DOM中的preventDefault()方法的作用相同) |
type | Element | 只读 | 事件的目标(与DOM中的target属性相同) |
type | String | 只读 | 被触发的事件的类型 |
IE 的 event 对象同样也包含与创建它的事件相关的属性和方法。其中很多属性和方法都有对应的或者相关的 DOM 属性和方法。与 DOM 的 event 对象一样,这些属性和方法也会因为事件类型的不同而不同,但所有事件对象都会包含下表所列的属性和方法。
属性/方法 | 类 型 | 读/写 | 说 明 |
---|---|---|---|
cancelBubble | Boolean | 读/写 | 默认值为false,但将其设置为true就可以取消事件冒泡(与DOM中的stopPropagation()方法的作用相同) |
returnValue | Boolean | 读/写 | 默认值为true,但将其设置为false就可以取消事件的默认行为(与DOM中的preventDefault()方法的作用相同) |
type | Element | 只读 | 事件的目标(与DOM中的target属性相同) |
type | String | 只读 | 被触发的事件的类型 |
因为事件处理程序的作用域是根据指定它的方式来确定的,所以不能认为 this 会始终等于事件目标。故而,最好还是使用 event.srcElement 比较保险。例如:
var btn = document.getElementById("myBtn");
btn.onclick = function(){
alert(window.event.srcElement === this); //true
};
btn.attachEvent("onclick", function(event){
alert(event.srcElement === this); //false
});
在第一个事件处理程序中(使用 DOM0 级方法指定的),srcElement 属性等于 this,但在第二个事件处理程序中,这两者的值不相同。
如前所述,returnValue 属性相当于 DOM 中的 preventDefault()方法,它们的作用都是取消给定事件的默认行为。只要将 returnValue 设置为 false,就可以阻止默认行为。来看下面的例子。
var link = document.getElementById("myLink");
link.onclick = function(){
window.event.returnValue = false;
};
这个例子在onclick事件处理程序中使用returnValue达到了阻止链接默认行为的目的。与DOM不同的是,在此没有办法确定事件是否能被取消。
相应地,cancelBubble 属性与 DOM 中的 stopPropagation()方法作用相同,都是用来停止事件冒泡的。由于 IE 不支持事件捕获,因而只能取消事件冒泡;但 stopPropagatioin()可以同时取消事件捕获和冒泡。例如:
var btn = document.getElementById("myBtn");
btn.onclick = function(){
alert("Clicked");
window.event.cancelBubble = true;
};
document.body.onclick = function(){
alert("Body clicked");
};
通过在 onclick 事件处理程序中将 cancelBubble 设置为 true,就可阻止事件通过冒泡而触发
document.body 中注册的事件处理程序。结果,在单击按钮之后,只会显示一个警告框。
四、事件类型
Web 浏览器中可能发生的事件有很多类型。如前所述,不同的事件类型具有不同的信息,而“DOM3
级事件”规定了以下几类事件。
- UI(User Interface,用户界面)事件,当用户与页面上的元素交互时触发;
- 焦点事件,当元素获得或失去焦点时触发;
- 鼠标事件,当用户通过鼠标在页面上执行操作时触发;
- 滚轮事件,当使用鼠标滚轮(或类似设备)时触发;
- 文本事件,当在文档中输入文本时触发;
- 键盘事件,当用户通过键盘在页面上执行操作时触发;
- 合成事件,当为 IME(Input Method Editor,输入法编辑器)输入字符时触发;
- 变动(mutation)事件,当底层 DOM 结构发生变化时触发。
- 变动名称事件,当元素或属性名变动时触发。此类事件已经被废弃,没有任何浏览器实现它们,
因此本章不做介绍。
除了这几类事件之外,HTML5 也定义了一组事件,而有些浏览器还会在 DOM 和 BOM 中实现其他
专有事件。这些专有的事件一般都是根据开发人员需求定制的,没有什么规范,因此不同浏览器的实现
有可能不一致。
DOM3 级事件模块在 DOM2 级事件模块基础上重新定义了这些事件,也添加了一些新事件。包括
IE9 在内的所有主流浏览器都支持 DOM2 级事件。IE9 也支持 DOM3 级事件。
参考
- 《JavaScript高级程序设计》
网友评论