DOM事件、事件流、事件对象、事件委托

本文主主要围绕以下四个部分展开:

  • DOM事件级别
  • 事件流(冒泡、捕获、DOM事件流)
  • 事件对象(event)
  • 事件委托

一、DOM事件级别

DOM级别:可分为四级:DOM0级,DOM1级,DOM2级和 DOM3级。查看详细的DOM级别可以戳这里哟~  

可以看到在DOM1标准内并未添加事件相关的东西。

所以DOM事件级别分别为:DOM0级事件处理,DOM2级事件处理和DOM3级事件处理

先了解一下HTML事件处理程序

某个元素支持的每种事件,都可以使用一个与相应事件处理程序同名的HTML特性来指定。这个特性的值是可以执行JavaScript的代码。





缺点:是HTML于JS强耦合,我们一旦需要修改函数名就得修改两个地方。

优点:不需要操作DOM来完成事件的绑定。

因为这个缺点所以后期开发人员摒弃HTML事件处理程序,转而使用JavaScript指定事件处理程序的原因。

1.DOM0级事件

el.οnclick=function(){}

var btn = document.getElementById('btn');
btn.onclick = function(){
    alert(this.innerHTML);
 }

在上述代码内移除使用了下方语句:

btn.onclick = null;

当希望为同一个元素/标签绑定多个同类型事件的时候(如给上面的这个btn元素绑定3个点击事件),是不被允许的,即只能绑定一个事件函数。DOM0事件绑定,给元素的事件行为绑定方法,这些方法都是在当前元素事件行为的冒泡阶段(或者目标阶段)执行的。

2.DOM 2级事件

el.addEventListener(event-name, callback, useCapture)

  • event-name: 事件名称,可以是标准的DOM事件
  • callback: 回调函数,当事件触发时,函数会被注入一个参数为当前的事件对象 event
  • useCapture: 默认是false,代表事件句柄在冒泡阶段执行
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。

3.DOM 3级事件

在DOM 2级事件的基础上添加了更多的事件类型。

  • UI事件,当用户与页面上的元素交互时触发,如:load、unload、resize、scroll
  • 焦点事件,当元素获得或失去焦点时触发,如:blur、focus
  • 鼠标事件,当用户通过鼠标在页面执行操作时触发如:dblclick、mouseup
  • 滚轮事件,当使用鼠标滚轮或类似设备时触发,如:mousewheel
  • 文本事件,当在文档中输入文本时触发,如:textInput
  • 键盘事件,当用户通过键盘在页面上执行操作时触发,如:keydown、keypress
  • 合成事件,当为IME(输入法编辑器)输入字符时触发,如:compositionstart
  • 变动事件,当底层DOM结构发生变化时触发,如:DOMsubtreeModified
  • 同时DOM3级事件也允许使用者自定义一些事件。

二、事件流

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标签,首先弹出的外层标签提示,然后是内层标签提示,正好与事件冒泡相反。

DOM事件流

事件流描述的是页面接收事件的顺序。

“DOM2级事件”规定的事件流包括三个阶段:事件捕获阶段处于目标阶段事件冒泡阶段

首先发生的是事件捕获,为截取事件提供了机会。然后是实际的目标接收事件,。最后一个阶段是冒泡阶段,可以在这个阶段对事件做出响应。

DOM事件、事件流、事件对象、事件委托_第1张图片

在DOM事件流内,实际的目标(

元素)在捕获阶段不会接收到事件。这意味着在捕获解读那事件从document到再到就停止了。下一阶段是“处于目标阶段”,于是事件在
上发生,并在事件处理中被看成是冒泡阶段的一部分。然后冒泡阶发生,事件又传回文档。

浏览器实现了一种特定操作:在捕获阶段触发事件对象上的事件,意味着有两次机会可以在目标对象上面操作事件。

 

 

三、事件对象

在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息。包括导致事件的元素,事件的类型以及其他与特定事件相关的信息。例如鼠标操作导致的事件对象中,会包含鼠标位置的信息,而键盘操作导致的事件对象中,会包含与按下键相关的信息,所有浏览器都支持event对象,但支持方式不同。

DOM中的事件对象

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

 

event.currentTarget与event.target

在事件处理程序内部,对象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()

IE中的事件对象

属性/方法 类型 说明
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)。

1.优点

  • 减少内存消耗,提高性能

假设有一个列表,列表之中有大量的列表项,我们需要在点击每个列表项的时候响应一个事件

  • item 1
  • item 2
  • item 3
  • ......
  • item n

如果给每个列表项一一都绑定一个函数,那对于内存消耗是非常大的,效率上需要消耗很多性能。借助事件代理,我们只需要给父容器ul绑定方法即可,这样不管点击的是哪一个后代元素,都会根据冒泡传播的传递机制,把容器的click行为触发,然后把对应的方法执行,根据事件源,我们可以知道点击的是谁,从而完成不同的事。

  • 动态绑定事件

在很多时候,我们需要通过用户操作动态的增删列表项元素,如果一开始给每个子元素绑定事件,那么在列表发生变化时,就需要重新给新增的元素绑定事件,给即将删去的元素解绑事件,如果用事件代理就会省去很多这样麻烦。

2.如何实现

接下来我们来实现上例中父层元素 #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事件机制

 

你可能感兴趣的:(javascript)