本文主主要围绕以下四个部分展开:
DOM级别:可分为四级:DOM0级,DOM1级,DOM2级和 DOM3级。查看详细的DOM级别可以戳这里哟~
可以看到在DOM1标准内并未添加事件相关的东西。
所以DOM事件级别分别为:DOM0级事件处理,DOM2级事件处理和DOM3级事件处理
先了解一下HTML事件处理程序
某个元素支持的每种事件,都可以使用一个与相应事件处理程序同名的HTML特性来指定。这个特性的值是可以执行JavaScript的代码。
缺点:是HTML于JS强耦合,我们一旦需要修改函数名就得修改两个地方。
优点:不需要操作DOM来完成事件的绑定。
因为这个缺点所以后期开发人员摒弃HTML事件处理程序,转而使用JavaScript指定事件处理程序的原因。
el.οnclick=function(){}
var btn = document.getElementById('btn');
btn.onclick = function(){
alert(this.innerHTML);
}
在上述代码内移除使用了下方语句:
btn.onclick = null;
当希望为同一个元素/标签绑定多个同类型事件的时候(如给上面的这个btn元素绑定3个点击事件),是不被允许的,即只能绑定一个事件函数。DOM0事件绑定,给元素的事件行为绑定方法,这些方法都是在当前元素事件行为的冒泡阶段(或者目标阶段)执行的。
el.addEventListener(event-name, callback, useCapture)
var btn = document.getElementById('btn');
btn.addEventListener("click", test, false);
function test(e){
e = e || window.event;
alert((e.target || e.srcElement).innerHTML);
btn.removeEventListener("click", test, false)
}
//IE9-:attachEvent()与detachEvent()。
//IE9+/chrom/FF:addEventListener()和removeEventListener()
在上述代码内移除使用了下方语句:
btn.removeEventListener("click", test, false)
IE9以下的IE浏览器不支持 addEventListener()和removeEventListener(),使用 attachEvent()与detachEvent() 代替,因为IE9以下是不支持事件捕获的,所以也没有第三个参数,第一个事件名称前要加on。
在DOM 2级事件的基础上添加了更多的事件类型。
JavaScript与HTML之间的交互是通过事件实现的。事件,是文档或浏览器窗口发生的一些特定的交互瞬间。可以使用侦听器(或处理程序)来预定事件,以便事件发生时执行相应的代码。这种在传统软件工程被称为观察者模式的模型,支持页面的行为(JavaScript代码)与页面的外观(HTML和CSS代码)之间的松散耦合。
IE的事件流是事件冒泡流,而Netscape提出的事件流是事件捕获流。
IE的事件流叫做事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。以下面的HTML页面为例:
在这里使用了el.addEventListener(event-name, callback, useCapture) ,最后一个参数为false或不加时,默认为事件冒泡。
这里先弹出内层事件,再弹出外层事件。
阻止事件冒泡:
child.addEventListener('click', function(e) {
alert('内层a标签事件');
e.stopPropagation();
}, false);
事件捕获的用意在于在事件到达预定目标之前捕获它。
和事件冒泡相反,事件捕获是自上而下执行,我们只需将addEventListener的第三个参数改为true即可。
此时我们点击a标签,首先弹出的外层标签提示,然后是内层标签提示,正好与事件冒泡相反。
事件流描述的是页面接收事件的顺序。
“DOM2级事件”规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。
首先发生的是事件捕获,为截取事件提供了机会。然后是实际的目标接收事件,。最后一个阶段是冒泡阶段,可以在这个阶段对事件做出响应。
在DOM事件流内,实际的目标(
浏览器实现了一种特定操作:在捕获阶段触发事件对象上的事件,意味着有两次机会可以在目标对象上面操作事件。
在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息。包括导致事件的元素,事件的类型以及其他与特定事件相关的信息。例如鼠标操作导致的事件对象中,会包含鼠标位置的信息,而键盘操作导致的事件对象中,会包含与按下键相关的信息,所有浏览器都支持event对象,但支持方式不同。
兼容DOM浏览器会将以恶搞event对象传入到事件处理程序中。无论指定事件处理程序时,使用什么方法(DOM0或DOM2级),都会传入event对象。
例子:
var btn = document.getElementById("myBtn");
btn.onclick = function(event){
console.log(event.type);
};
btn.addEventListener("click", function(event){
console.log(event.type);
}, false);
上述两个方法弹出结果一致。
event对象包含与创建它的特定事件有关的属性和方法。触发的事件类型不同,可用的属性和方法也不一样。不过,所有的事件都会有下表列出的成员。
属性/方法 | 类型 | 说明 |
---|---|---|
bubbles | Boolean | 表明事件是否冒泡 |
cancelable | Boolean | 表面是否可以取消事件的默认行为 |
currentTarget | Element | 其事件处理程序当前正在处理事件的那个元素 |
defaultPrevent | Boolean | 为true表示已经调用了preventDefault() |
detail | Integer | 与事件相关的细节 |
eventPhase | Integer | 调用事件处理程序的阶段:1.捕获2.处于目标3.冒泡 |
preventDefault() | Function | 取消事件的默认行为。如果cancelable是true,则可以使用这个方法 |
stopImmediatePropagation() | Function | 取消事件的进一步取消或冒泡,同时阻止任何事件处理程序被调用 |
stopPropagation() | Function | 取消事件的进一步取消或冒泡,如果cancelable是true,则可以使用这个方法 |
target | Element | 事件的目标 |
trusted | Boolean | 为true表示事件是浏览器生成,为false表示事件由开发人员通过JavaScript创建 |
type | String | 被触发的事件的类型 |
view | AbstractView | 与事件关联的抽象视图,等同于发生事件的window |
在事件处理程序内部,对象this始终等于currentTarget的值,而target则包含事件的实际目标。
document.body.onclick = function(event){
alert(event.currentTarget === document.body); //true
alert(this === document.body); //true
alert(event.target === document.getElementById("myBtn")); //true
}
按钮是click的真正目标,由于按钮没有事件,然后冒泡到了body,事件在body处理。
阻止特定事件的默认行为:event.preventDefault()
立即停止事件在DOM层次的传播:event.stopPropagation()
属性/方法 | 类型 | 说明 |
---|---|---|
cancelBubble | Boolean | 默认false,但是为true时,可以取消冒泡(与DOM中的stopPropagation()作用相同) |
returnValue | Boolean | 默认true,但是为false时,可以取消事件的默认行为(与DOM中的preventDefault()作用相同) |
srcElement | Element | 事件的目标(与DOM的target属性相同) |
type | String | 被触发的事件的类型 |
跨浏览器的事件对象(兼容处理)
var EventUtil = {
name: "eventutil",
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.cancelBubble = false;
}
}
}
去除a链接的点击跳转行为:
a标签仅仅是想当做一个普通的按钮,点击实现一个功能,不想页面跳转,也不想锚点定位。
1. 设置空链接
链接
2.直接return false;
链接
3.阻止特定事件的默认行为
链接
由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件的代理(delegation)。
假设有一个列表,列表之中有大量的列表项,我们需要在点击每个列表项的时候响应一个事件
- item 1
- item 2
- item 3
......
- item n
如果给每个列表项一一都绑定一个函数,那对于内存消耗是非常大的,效率上需要消耗很多性能。借助事件代理,我们只需要给父容器ul绑定方法即可,这样不管点击的是哪一个后代元素,都会根据冒泡传播的传递机制,把容器的click行为触发,然后把对应的方法执行,根据事件源,我们可以知道点击的是谁,从而完成不同的事。
在很多时候,我们需要通过用户操作动态的增删列表项元素,如果一开始给每个子元素绑定事件,那么在列表发生变化时,就需要重新给新增的元素绑定事件,给即将删去的元素解绑事件,如果用事件代理就会省去很多这样麻烦。
接下来我们来实现上例中父层元素 #list 下的 li 元素的事件委托到它的父层元素上:
// 给父层元素绑定事件
document.getElementById('list').addEventListener('click', function (e) {
// 兼容性处理
var event = e || window.event;
var target = event.target || event.srcElement;
// 判断是否匹配目标元素
if (target.nodeName.toLocaleLowerCase() === 'li') {
console.log('the content is: ', target.innerHTML);
}
});
本文主要讲了DOM事件级别(DOM0、DOM2、DOM3)等级别的事件类别,还分析了事件流机制冒泡、捕获、DOM事件流等,简介了事件对象(event)及其内部的属性,DOM事件对象及IE事件对象,兼容处理等。及事件委托(代理)及示例。
参考文档:DOM 事件深入浅出(一)
DOM事件机制