JS事件流与事件处理程序


事件流

首先需要了解一个问题,当指向一组同心圆的圆心的时候,此时触发的是所有圆的圆心。同理,如果单击了某个按钮,那么这个按钮的父容器,爷爷容器,甚至说整个页面其实都被单击了,所以,这个触发的顺序,就是咱要说的事件流。

事件流描述的是从页面接收事件的顺序,IE的事件流是冒泡,而Netscape是事件捕获。没错,反的~

事件冒泡
IE的事件流,即时间开始的时候由最具体的元素(就你碰的那个)接收,然后逐级向上传播到一个不具体的节点(document),来个栗子:

<!DOCTYPE html>
<html>
<head>
    <title>我最瘦了</title>
</head>
<body>
    <div>点我点我点我</div>
</body>
</html>

点div,向上传播到,,然后是document。
所有现代浏览器都支持冒泡,但在具体实现上还是有一定的区别的。IE5.5以及更早版本的时间冒泡会跳过,IE9,Firefox,Chrome和Safari则将事件一直冒泡到window。

插播:这里应该也会有人对于window和document的概念有一点蒙,简单说下,每个载入浏览器的 HTML 文档都会成为 Document 对象,Document 对象使我们可以从脚本中对 HTML 页面中的所有元素进行访问,而Window 对象表示浏览器中打开的窗口,Document 对象是 Window 对象的一部分,可通过 window.document 属性对其进行访问。)

事件捕获
与冒泡相反,最具体的那个节点最后接收到事件。事件捕获的用意在于在事件到达预定目标之前捕获它。上面的例子就是从document到div的顺序,事件沿dom树依次向下。

虽然事件捕获是netscape唯一支持的事件流模型,IE9,Firefox,Chrome,Safari,Opera也都支持这种事件流模型。尽管DOM2级事件要求从document对象开始传播,但是这些个浏览器也都还是从window对象开始捕获事件的。

老版本不支持,用事件捕获的场景不多,建议放心的使用冒泡,有特殊需要再去用捕获。(可以通过addEventListener方法的第三个参数来决定使用冒泡还是捕获。)

DOM事件流
包括三个阶段:事件捕获阶段,目标阶段和冒泡阶段。
DOM事件流中,实际的被触发的目标元素在捕获阶段中不会接收到事件。就是说在捕获阶段,事件从document到html到body就停止了,下一个阶段则是“目标阶段”,事件在div上发生并且被看做是冒泡阶段的一部分,然后冒泡阶段发生又被传回文档。
上图!
这里写图片描述

DOM2级事件明确要求捕获阶段不会涉及事件目标,但是IE9,Firefox,Chrome,Safari,Opera9.5以及更高版本都会在捕获阶段触发目标对象上的事件…

IE8及更早版本不支持DOM事件流


事件处理程序

用户和浏览器执行的操作有click,load,mouseover等等,那事件处理程序就是onclick,onload,onmouseover这些~以on开头,响应这些操作事件的函数就是事件处理程序,侦听器一样,是函数~

HTML事件处理程序

<input type="button" onclick="alert(event.type)" />
<input type="button" onclick="alert(this.value)" />
<input type="button" onclick="showMessage(e)" />

事件处理程序中的代码在执行时,有权利访问全局作用域中的任何代码。(包括script标签下定义的的或者外部文件内的)

通过event对象可以直接访问事件对象,函数内部中的this是目标元素

属性设置为null可以删除事件处理程序

btn.onclick = null;

缺点:

  1. 时间差问题,在事件处理程序还不具备执行条件的时候,出发dom上的事件
  2. 扩展事件处理程序的作用域链在不同的浏览器中会导致不同结果,不同的js引擎遵循的标识符解析规则存在差异,很可能会在访问非限定成员的时候出错。
  3. js代码与html紧密耦合

DOM0级事件处理程序

var btn = document.getElementById("myBtn");
btn.onclick = function(){
    alert(this.id);
}

这里可以在事件处理程序中通过this访问元素的任何属性和方法,this是目标元素

用下面这种方式可以删除事件处理程序

btn.onclick = null;

DOM2级事件处理程序

var btn = document.getElementById("myBtn");
btn.addEventListener("click",function(){
    alert(this.id);
},false);
//三个参数:事件名称,事件处理程序,最后这个参数true:捕获阶段调用前面的方法;false:冒泡阶段调用方法

与DOM0一样,事件处理程序也是在其依附的元素的作用域中运行,this是目标元素

DOM2事件处理程序与前两者不一样的就是,可以添加多个事件,例如给一个dom添加了两个点击事件,则会按照绑定的顺序依次执行。

解除事件绑定,removeEventListener第二个参数传入和绑定时候一样的参数即可

btn.removeEventListener("click",function(){
    alert(this.id);
},false);

嗯,上面这么写是不好使的,为什么?因为第二个参数是匿名函数!就算和绑定的时候的参数一模一样,但是也是一个新的函数。

如果真的想要把函数移除,那绑定和解绑都要用一样的函数名,来看代码:

var btn = document.getElementById("myBtn");
var handler = function(){
    alert(this.id);
}
btn.addEventListener("click",handler,false);
btn.removeEventListener("click",handler,false);

懂了伐~
ps一句,一般第三个参数都要false,表示在冒泡阶段去执行事件,可以最大限度的兼容各种浏览器。如果不是机器特殊的情况,都不建议传入true在事件捕获阶段去注册事件处理程序。

IE的事件处理程序
绑定事件attachEvent(),解绑detachEvent()。两个参数,事件名称和要进行的操作函数。通过这个方法添加的事件都会被添加到冒泡阶段。

var btn = document.getElementById("myBtn");
var handler = function(){
    alert(this===window); //true
}
btn.attachEvnet("onclick",handler);
btn.detachEvent("onclick",handler);

需要注意几点:

  1. 事件名称是on***,例如onclick,不是像中的click,可以理解为第一个参数是处理程序的名字,而不是操作的名字
  2. 与前几个事件处理程序的作用域不一样。前几个都是在所属元素的作用域下进行,而这个是在全局作用域下进行,如上代码,this===window。
  3. 这个也可以像DOM2一样为一个dom添加多个事件,不过执行顺序与addeventListener相反,换句话说,按照绑定顺序的相反顺序来触发
  4. 解绑函数要传入一样的函数名引用,不要传入匿名函数哦~
  5. 只有IE和Opera支持这个
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值