DOM事件流

在DOM中添加事件总是使用三种方法,

第一种使用HTML中的事件处理程序:

<button onclick=' $$ '></button>

第二种:使用在JavaScript中添加事件处理程序:

var s =document.getElementById('id');
s.oncilck=function(){}

第三种使用 addEventListener 方法注册事件处理程序:

document.getElementById('id').addEventListener('click',function(){})//注意是click

一直是这样用的,却没有理解使用的弊端和注意的问题,现在总结一下这三者DOM事件处理方法的优劣。

一、事件流

事件流有两种,事件冒泡事件捕获,它表示当用户触发了某个页面元素的动作,应该由怎样的方式向“观察者”传递;就像是身为校长的你,学生发生了一起斗殴事件,你是通过挨个年级-班级去找到滋事者(事件捕获);还是通过一个学生主动告诉你事情发生的经过(事件冒泡)。

1、事件冒泡

假如一篇文档的结构:

<html>
<head> </head>
<body>
<div></div>
</body>
</html>

当点击div元素 ,触发了click事件,那么冒泡传递的方式是这样的,

2、事件捕获

自然是反方向的:

3、DOM事件流

很多面试会有问到这个问题,实际上DOM事件流是DOM2级事件中规定的,它包括,事件捕获阶段,目标发生阶段,和事件冒泡阶段。

 

值得注意的是,div元素不会在捕获阶段接受事件,也就是捕获的过程到body后就停止了,接下来是目标阶段;在事件处理中属于冒泡阶段的一部分,

 DOM2中规定捕获阶段不会设计目标事件,但是高版本浏览器没有遵循规定;因此就有两个机会在目标对象中操作事件。

 二、事件处理程序

事件的名称 click ;load;mouseover;事件处理程序以‘on’开头;因此click事件的事件处理程序就是onclickload事件的事件处理程序就是onload

1、HTML事件处理程序

 HTML事件处理程序可以直接在事件处理程序中,添加执行的函数,也可以进行调用其他地方定义的脚本;

<button oncilck="alert('hello world!')"></button>//执行代码直接添加到事件中
<script>
function hello(){
alert('hello,world!')
}
</script>

<button onclick='hello()'></button>//调用其他脚本

HTML事件处理程序特性

  • 会创建一个封装着元素属性值的函数,这个函数中有一个局部变量event,也就是事件对象。
  • 时间处理程序函数在执行时,有权访问全局作用域中的任何代码。
<input type='button' value='click me' onclick='alert(this.value)'>//click me this值指向发生事件的目标元素;
<input type='button' value='click' onclick='alert(event.type)'>//click 通过event对象可以访问事件对象;

HTML事件处理程序缺点

  • 失去响应。如果定义的脚本在触发事件元素的后面进行定义的,很可能在没有加载脚本之前;用户点击了元素,会失去响应;(JavaScript引擎是逐行读取代码的)
  • HTML与JavaScript高度耦合,缺乏可维护性和增加维护成本。

2、DOM 0 级事件处理程序

JavaScript中常见的处理事件的方式,通过将函数赋值给一个事件处理程序属性;

var but=document.getElementById('id');
but.onclick=function(){
    alert(this.value)
}
  • DOM0级方法指定的事件处理程序,被认为是元素的方法,因此this指向当前引用元素。

  • 删除指定的事件程序可以重新将事件引用赋值为null,会自动注销已经注册的事件。
but.onclick=null;//阻止事件处理的方式,设置null;

3、DOM 2级事件处理程序

通过addEventListener()    removeEventListener(),方法注册和删除事件处理程序,接受3个参数,事件名,处理函数,布尔值;

var but=document.getElementById('id');
but.addEventListener('click',function(){
    alert('this.value');
},false);

布尔值true表示在事件流捕获阶段触发调用,布尔值false 表示在冒泡阶段调用事件处理程序。

注意:

  • 第二个参数是事件名,不是事件处理函数名, ‘click’而不是‘onclick’,与前两个方式不同。
  • 可以添加多个事件处理程序;处理的顺序按照注册的顺序执行。
var but=document.getElementById('id');
but.addEventListener(
'click',function(){ alert('this.value'); },false);
but.addEventListener(
'click',function(){ alert('hello world'); },false);
  • 匿名函数无法通过removeEventListener()方法移除事件处理程序,因为两次的匿名函数不是同一个函数,
var but=document.getElementById('id');

but.addEventListener('click',function(){
    alert('hello world');
},false);

but.removeEventListener('click',function(){
    alert('hello world');
},false);//无效,因为第二个参数是完全不同的匿名函数,只是定义相同;
var but=document.getElementById('id');

function hello(){
    alert('hello world')
}

but.addEventListener('click',hello,false);
but.removeEventListener('click',hello,false)//有效,使用相同函数

4、IE事件处理程序

IE使用attachEvent()  detachEvent()两个方法添加事件处理,这两个方法分别接受两个参数,事件处理名称,事件处理函数;由于IE8更早版本只支持事件冒泡,因此通过attachEvent() 添加的时间处理程序会被添加到冒泡阶段。
注意

  • attachEvent() 第一个参数是“onclick” 而不是“click”;
  • attachEvent() 也可以添加多个事件,不过执行的顺序完全相反;
  • 可以通过 detachEvent() 方法移除事件,和removeEventListener() 类似;不能移除匿名函数。
var but=document.getElementById('id');
function hello(){
    alert('hello world')
}

but.attachEvent('onclick',hello);
but.attachEvent('onclick',function(){
    alert('this.id')
})
//先 弹出id ,后弹出 hello world

 

posted @ 2018-04-17 13:07  恩恩先生  阅读(704)  评论(1编辑  收藏  举报