DOM的三种事件模型和牵扯到的事件e

引子(略长,看事件模型可以直接跳到后面):

事件:

什么是事件呢?直观的说就是网页上发生的事情,大部分是指用户的鼠标动作和键盘动作,如点击、移动鼠标、按下某个键。

为什么说大部分呢,因为事件不单单只有这两部分,还有其他的例如document的load和unloaded。只不过我们更加关注的是用户的操作。

事件被封装成一个event对象,包含了该事件发生时的所有相关信息(event的属性)以及可以对事件进行的操作(event的方法)。

 

e常用属性:

各个浏览器中鼠标位置的属性 offsetX layerX PageX clientX (自由拖动框,防止文字选中)

DOM 的事件操作(监听和触发),都定义在EventTarget接口。所有节点对象都部署了这个接口,其他一些需要事件通信的浏览器内置对象(比如,XMLHttpRequest、AudioNode、AudioContext)也部署了这个接口。

该接口主要提供三个实例方法。

addEventListener:绑定事件的监听函数

removeEventListener:移除事件的监听函数

dispatchEvent:触发事件

另外我想你很可能听说过事件驱动, 但是事件驱动到底是什么?为什么说浏览器是事件驱动的呢?

事件驱动通俗地来说就是什么都抽象为事件

  • 一次点击是一个事件
  • 键盘按下是一个事件
  • 一个网络请求成功是一个事件
  • 页面加载是一个事件
  • 页面报错是一个事件
  • ...

浏览器依靠事件来驱动 APP 运行下去,如果没有了事件驱动,那么 APP 会直接从头到尾运行完,然后结束,事件驱动是浏览器的基石。

 

DOM到底有几级?

Tip: {文档对象模型(Document Object Model)。就是一个编程接口,就是一套API, 针对HTML文档、XML等文档的一套API,用来访问或操作HTML文档、XHTML文档、XML文档中的节点元素。JavaScript 可以通过 DOM 来访问和操作HTML文档所有的元素及其属性。}

首先:是没有DOM0级的。在平时阅读的时候可能会读到DOM0级(DOM Level0)的字眼。实际上,DOM0级标准是不存在的,所谓的DOM0级是DOM历史坐标中的一个参照点而已,具体说呢,DOM0级指的是IE4和Netscape 4.0这些浏览器最初支持的DHTML..大概2000年的时候争论过DOM0的问题,最后结论大概是,没有官方形成此标准,不是W3C规范.。

DOM1级(DOM Level 1)于1998年10月成为W3C的推荐标准。DOM1级由两个模块组成:DOM核心(DOM Core)和DOM HTML。其中,DOM核心规定的是如何映射基于XML的文档结构,以便简化对文档中任意部分的访问和操作。DOM HTML模块则在DOM核心的基础上加以扩展,添加了针对HTML的对象和方法。

如果说DOM1级的目标主要是映射文档的结构,那么DOM2级的目标就要宽泛多了。DOM2级在原来DOM的基础上又扩充了(DHTML一直都支持的)鼠标和用户界面事件、范围、遍历(迭代DOM文档的方法)等细分模块,而且通过对象接口增加了对CSS(Cascading Style Sheets,层叠样式表)的支持。DOM1级中的DOM核心模块也经过扩展开始支持XML命名空间。

DOM3级则进一步扩展了DOM,引入了以统一方式加载和保存文档的方法–在DOM加载和保存(DOM Load and Save)模块中定义;新增了验证文档的方法–在DOM验证(DOM Validation)模块中定义。DOM3级也对DOM核心进行了扩展,开始支持XML 1.0规范,涉及XML Infoset、XPath和XML Base。

 

第1种DOM事件模型:原始事件模型original event model(DOM 1级)

在原始事件模型中, 事件发生后没有传播的概念,没有事件流。事件发生,马上处理,完事,就这么简单,具有极好的跨浏览器优势,会以最快的速度绑定。

监听函数只是元素的一个属性值,通过指定元素的属性值来绑定监听器。书写方式有两种:

①   HTML代码中指定属性值:

<input type=”button” onclick=”func1()” />

       注意:为某一个元素的同一个行为绑定不同的方法在行内会分别执行

<div id="box" onclick="fun1();fun2()">点我</div>
<script>
	// 某一个元素的同一个行为绑定不同的方法在行内会分别执行
	function fun1() {
		console.log('方法1');
	}
	function fun2() {
		console.log('方法2');
	}
	// 执行 方法1		// 执行方法2
</script>


// ===============================================================

// 通常情况下事件监听函数如果返回一个值并且是false,则会阻止浏览器执行默认的动作。无论用html还   // 是js,都是把一个函数赋值给文档元素,在事件监听函数被调用时候它是作为产生事件的元素的放法调用
// 的,所以this引用的是那个目标元素(例子中的Input对象)。

      注意:为某一个元素的同一个行为绑定不同的方法在script标签中后面的方法会覆盖前面的方法

<div id="box">点我</div>
<script>
	// 某一个元素的同一个行为绑定不同的方法在script标签中后面的方法会覆盖前面的方法
	var box = document.getElementById('box');
	box.onclick = fun1;
	box.onclick = fun2;
	function fun1() {
		console.log('方法1');
	}
	function fun2() {
		console.log('方法2');
	}
	// 执行方法2;方法2覆盖方法1,所有方法1不执行
</script>

②   在js代码中指定属性值:

document.getElementsByTagName(‘input’)[0].onclick = func1

删除事件处理监听器/解除绑定:只要将对应事件属性设为null即可。

box.onclick = null;

优点:所有浏览器都兼容

缺点

           1)逻辑与显示没有分离;

           2)相同事件的监听函数只能绑定一个,后绑定的会覆盖掉前面的,如:a.onclick = func1; a.onclick = func2;将只会执行func2中的内容。

           3)无法通过事件的冒泡、委托等机制(后面系列会讲到)完成更多事情。  

在当前web程序模块化开发以及更加复杂的逻辑状况下,这种方式显然已经落伍了,所以在真正项目中不推荐使用,平时写点博客小例子啥的倒是可以,速度比较快。

 

第2种DOM事件模型:(DOM 2级)

在2级DOM中除了定义了一些DOM相关的操作之外还定义了一个事件模型 ,这个标准下的事件模型就是我们所说的2级DOM事件模型2级DOM的事件传播在2级DOM中,当事件发生在节点时,目标元素的事件处理函数就被触发,而且目标的每个祖先节点也有机会处理那个事件。

这个模型参考了IE的气泡模型而制定的,它是由w3c制定的规范.在原始模型中事件一旦发生就直接调用事件句柄,没有其它的事件传播过程.

而在DOM2模型中事件有一个特殊的传播过程,分为三个阶段: (1).事件捕获阶段,(2).事件目标阶段,(3).事件冒泡阶段

dom2新增冒泡和捕获的概念,并且支持一个元素节点绑定多个事件。

事件传播(event propogation):

一次事件的发生包含三个过程:(1).事件捕获阶段(capturing phase),(2).事件目标阶段(target phase),(3).事件冒泡阶段(bubbling phase)

在这里插入图片描述

事件捕获:当某个元素触发某个事件(如onclick),顶层对象document就会发出一个事件流,随着DOM树的节点向目标元素节点流去,直到到达事件真正发生的目标元素。在这个过程中,事件相应的监听函数是不会被触发的。事件被从document一直向下传播到目标元素,在这过程中如果有哪个祖先元素对该事件感兴趣可以注册自己的处理函数.

事件目标:当到达目标元素之后,执行目标元素该事件相应的处理函数。如果没有绑定监听函数,那就不执行。

事件冒泡:从目标元素开始,往顶层元素传播,一直上升到达document。途中如果有节点绑定了相应的事件处理函数,这些函数都会被一次触发。

虽然所有的事件类型都会经历captruing phase事件捕获阶段但是只有部分事件会经历bubbling phase冒泡阶段,例如submit事件就不会被上浮,不会被冒泡。

在整个的事件传播过程中可以调用event.stopPropagation()来停止事件的传播,调用preventDefault()来阻止浏览器的默认行为.

此处可参阅我写的原创文章: JS中的事件委托 获得更详细的理解。

绑定

DOM2级事件是通过addEventListener绑定的事件,addEventListener有三个参数 事件名称、事件回调、捕获/冒泡

<div id="box">点我</div>
<script>
 	var box = document.getElementById('box');
	box.addEventListener('click', fun1,false);
	box.addEventListener('click', fun2,false);
	function fun1() {
		console.log('方法1');
	}
	function fun2() {
		console.log('方法2');
	}
	// 执行方法1		// 执行方法2
</script>



btn.addEventListener('click',function(){
    console.log('btn')
},true)
box.addEventListener('click',function(){
    console.log('box')
},false)

         设置为true,则事件在捕获阶段执行,为false则在冒泡阶段执行。

删除DOM 2事件处理程序,通过removeEventListener

box.removeEventListener('click', fun2,false);

 

第3种DOM事件模型:IE事件模型:

IE模型也提供了一个event对象封装了事件的详细信息,但是IE不把该对象传入事件处理函数,由于在任意时刻只会存在一个事件,所以IE把它作为全局对象window的一个属性,IE中的事件传播模式对应于DOM2的第二和第三阶段,首先执目标元素的处理函数,然后向上传播到达document,ie中只能能捕捉鼠标事件,而DOM2中可以捕捉所有的事件,IE中注册和删除事件处理函数的方法也不同于DOM2.

IE下的DOM2事件通过attachEvent绑定;可以给某一个元素的同一个行为绑定不同的方法在行内会分别执行。

IE事件只支持冒泡,所以事件流有两个阶段:

  1. 事件处理阶段:事件在达到目标元素时,触发监听事件。
  2. 事件冒泡阶段:事件从目标元素冒泡到 document,并且一次检查各个节点是否绑定了监听函数,如果有则执行。

IE不把该对象传入事件处理函数,由于在任意时刻只会存在一个事件,所以IE把它作为全局对象window的一个属性,为求证其真伪,使用IE8执行代码alert(window.event),结果弹出是null,说明该属性已经定义,只是值为null(与undefined不同)。难道这个全局对象的属性是在监听函数里才加的?于是执行下面代码:

window.onload = function (){alert(window.event);}

setTimeout(function(){alert(window.event);},2000);

结果第一次弹出【object event】,两秒后弹出依然是null。由此可见IE是将event对象在处理函数中设为window的属性,一旦函数执行结束,便被置为null了。

总结:Event对象不是传递给事件监听函数,而是通过window对象的event属性访问Event对象.

IE的事件模型只有两步,先执行元素的监听函数,然后事件沿着父节点一直冒泡到document。冒泡已经讲解过了,这里不重复。

IE模型下的事件监听方式也挺独特,

绑定监听函数的方法是:(事件监听函数注册没有addEventListener,只有attachEvent)

attachEvent( “eventType”,“handler”); //其中evetType为事件的类型,如onclick,注意要加’on’。

IE事件模型没有capturing阶段所以调用attachEvent相当于调用addEvetnListener且第三个参数为false:

document.getElementById("myTest").attachEvent("onclick", function(){alert(1)});

相当于:

document.getElementById("myTest").addEventListener("click", function(){alert(1)}, false);

此外: 用attachEvent注册的函数将被作为全局函数调用,而不是作为发生事件的文档元素的方法,也就是说this引用的是window对象,而不是事件的目标元素。

解除事件监听器的方法是:

 detachEvent(“eventType”,“handler” )

事件处理函数的注册和删除是通过元素的attachEvent("eventType","handler") and detachEvent("eventType","handler" ),与dom2不同的是eventType有on前缀

特点:
1、传播过程只起泡,不捕捉。   起泡中断方法:window.ecent.cancelBubble=true;
2、Event对象不是事件处理程序的函数参数,而是window的全局变量。
3、事件注册函数:attachEvent()和反注册:detachEvent().

IE的事件模型已经可以解决原始模型的三个缺点,但其自己的缺点就是兼容性,只有IE系列浏览器才可以这样写。感觉很麻烦吧?因此我们一般会借助现有框架或类库已经封装好的,比如jQuery,

回顾下缺点:

           1)逻辑与显示没有分离;

           2)相同事件的监听函数只能绑定一个,后绑定的会覆盖掉前面的,如:a.onclick = func1; a.onclick = func2;将只会执行func2中的内容。

           3)无法通过事件的冒泡、委托等机制(后面系列会讲到)完成更多事情。 

 

延伸(DOM 3级)

DOM3级事件在DOM2级事件的基础上添加了更多的事件类型,全部类型如下:

同时DOM3级事件也允许开发人员自定义一些事件。

事件:

键盘事件(DOM0级事件支持)
            (1)键盘事件包括三个:keydown 、 keypress 、 keyup。
            (2)键码,event对象的keyCode属性中会包含一个代码,与键盘上一个特定的键对应。
                        对应的键码请查表。
HTML事件
load、unload、abort、error、select、change、submit、reset、resize、scroll、focus、blur。
多数HTML事件都与window对象或表单控件相关。

 

 

参考资料:

《JavaScript高级程序设计》

关于DOM级别的一些问题,DOM0,DOM1,DOM2

DOM0、DOM1、DOM2、DOM3事件区别

js事件模型

Javascript事件模型系列(一)事件及事件的三种模型

JS中DOM0,DOM2,DOM3级事件模型解析

浏览器三种事件处理的模型

3.1. Event dispatch and DOM event flow

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值