一、事件流

事件流,描述的是页面中接受事件的顺序,不过,IE的事件流是事件冒泡流,而Netscape Communicator的事件流是事件捕获型。标准同时支持两种事件模型,即捕获型事件与冒泡型事件,但是,捕获型事件先发生。

两种事件流都会触发DOM中的所有对象,从document对象开始,也在document对象结束(大部分兼容标准的浏览器会继续将事件是捕捉/冒泡延续到window对象)JavaScript与HTML之间的交,通过事件实现。常用观察员模式,使用侦听器来预定事件,以便事件发生时执行相应的代码。

DOM(文档对象模型)结构是一个树型结构,当一个HTML元素产生一个事件时,该事件会在元素结点与根节点之间按特定的顺序传播,路径所经过的节点都会收到该事件,这个传播过程可称为DOM事件流。

二、事件句柄和事件监听器

事件句柄与事件监听器的最大不同之处是使用事件句柄时一次只能插接一个事件句柄,但对于事件监听器,一次可以插接多个。现在大多数浏览器都内置了一些更高级的事件处理方式,即,事件监听器,这种处理方式就不受一个元素只能绑定一个事件句柄的限制。

获取事件的目标

HTML如下:

body id="myBody">
<button id="myButton">click</button>
</body>

1. IE下的事件监听器:attachEvent接受两个参数。第一个参数是事件类型名,第二个参数eventListener是回调处理函数。

在IE中,每个元素和window对象都有两个方法:attachEvent方法和detachEvent方法。

IE 事件对象使用 event 的 srcElement 属性获取事件目标。

var btn = document.getElementById("myButton");
btn.attachEvent("onclick", function(event) {
alert(event.srcElement.id); // myButton
});

2. DOM标准下的事件监听器:addEventListener

addEventListener方法接受三个参数。第一个参数是事件类型名,值得注意的是,这里事件类型名称与IE的不同,事件类型名是没’on’开头的;第二个参数eventListener是回调处理函数(即监听器函数);第三个参数注明该处理回调函数是在事件传递过程中的捕获阶段被调用还是冒泡阶段被调用 ,通常此参数通常会设置为false(为false时是冒泡),如果将其值设置为true,那就创建一个捕捉事件监听器。

通过addEventListener方法添加的事件处理函数,必须使用removeEventListener方法才能删除,而且要求参数与添加事件处理函数时addEventListener方法的参数完全一致(包括useCapture参数),否则将不能成功删除事件处理函数。

标准事件对象使用 event 的 target 属性获取事件目标:


var btn = document.getElementById('myButton');
btn.addEventListener("click", function(event) {
alert(event.target.id); // myButton
});

三、取消事件默认行为

html结构如下:

<div id="oDiv">
<a id="oA" href="http://baidu.com">
百度一下,你就知道。
</a>
</div>

正常情况下,我们点击a链接,会跳转到baidu.com,但当使用了e.preventDefault().

JS代码如下:

var a = document.getElementById("oA");

    //获取div
var oDiv = document.getElementById('oDiv'); //dom0级绑定事件方法
a.onclick=function(e){
e.preventDefault();
}
// 旧版本IE不支持捕获,一般使用冒泡。
oDiv.addEventListener("click", function (e) {
e.preventDefault();
}, false);

四、禁止冒泡

一、正常情况下:

//关于阻止事件冒泡.ie678用attachEvent
a.addEventListener("click", function (e) {
alert(1);
}, false);//冒泡 oDiv.addEventListener("click", function (e) {
alert(2)
}, false);//冒泡 oDiv.addEventListener("click", function (e) {
alert(3);
}, true);//捕获,捕获先发生

第3个参数设置为false时候为冒泡,先捕获,后冒泡。这里弹出顺序依次是:3,1,2

二、禁止冒泡时:用到stopPropagation

    //关于阻止事件冒泡.ie678用attachEvent
a.addEventListener("click", function (e) {
e.stopPropagation();//阻止冒泡/捕获
alert(1);
}, false);//冒泡 oDiv.addEventListener("click", function (e) {
alert(2)
}, false);//冒泡 oDiv.addEventListener("click", function (e) {
e.stopPropagation();
alert(3);
}, true);//捕获,捕获先发生

这时候顺序是:3,不会出现1,2。因为在第3个函数里用到了stopPropagation,而且捕获比冒泡事件先发生。所以只会出现3.

注意:e.cancelBubble = true对应取消冒泡;e.returnValue = true对应阻止默认行为

五、addEventListener与attachEvent区别

1. 支持的浏览器

    addEventListener在支持DOM2的浏览器中使用,如FF, Chrome等

    attachEvent为IE所用

2. 处理程序执行阶段

    addEventListener的第三个参数为true时,在捕获阶段执行,为false时,在冒泡阶段执行

    attachEvent的均在冒泡阶段执行

3. 作用域

    addEventListener的作用域为元素作用域,this为element的引用

    addEvent的为全局作用域,this为window的引用

4. 事件处理程序执行顺序

    addEventHander:执行顺序与添加顺序一致

    attachEvent:执行顺序与添加顺序相反

5. 针对的事件不同

    attachEvent中的事件带on 

    addEventListener中的事件不带on

六、冒泡的用处

例如:有一个10列、100行的HTML表格,假如有一次你需要让表格中的每一个单元格在被点击的时候变成可编辑状态。

如果把事件处理器加到这1000个单元格会产生一个很大的性能问题,并且有可能导致内存泄露甚至是浏览器的崩溃。

相反地,使用事件代理的话,只需要把一个事件处理器添加到table元素上就可以了,这个函数可以把点击事件给截下来,并且判断出是哪个单元格被点击了。

比如:有一个 table元素,ID是“report”,我们为这个表格添加一个事件处理器以调用editCell函数。editCell函数需要判断出传到table 来的事件的目标元素。考虑到我们要写的几个函数中都有可能用到这一功能,所以我们把它单独放到一个名为getEventTarget的函数中:


function getEventTarget(e) {
e = e || window.event;
return e.target || e.srcElement;
}

e这个变量表示的是一个事件对象,我们只需要写一点点跨浏览器的代码来返回目标元素,在IE里目标元素放在srcElemtn属性或event.toElement属性中,而在其它浏览器里则是target或event.relatedTarget属性。

接下来就是editCell函数了,这个函数调用到了 getEventTarget函数。一旦我们得到了目标元素之后,剩下的事情就是看看它是否是我们所需要的那个元素了。

function editCell(e) {
var target = getEventTarget(e);
if(target.tagName.toLowerCase() === 'td') {
// DO SOMETHING WITH THE CELL
}
}

通过事件冒泡,那些需要创建的以及驻留在内存中的事件处理器少了。这样我们就提高了性能,并降低了崩溃的风险。

参考:《JavaScript高级程序设计》

JavaScirpt事件处理的更多相关文章

  1. JavaScript权威设计--事件处理介绍(简要学习笔记十七)

    1.事件相关概念 事件类型:一个用来说明发生什么类型事件的字符串 事件目标:是发生的事件或与之相关的对象. 事件处理程序(事件监听程序):是处理货响应事件的函数. 事件对象:是与特定事件相关并且包含有 ...

  2. JavaScript移除绑定在元素上的匿名事件处理函数

    前言: 面试的时候有点蒙,结束之后想想自己好像根本就误解了面试官的问题,因为我理解的这个问题本身就没有意义.但是当时已经有一些思路,但是在一个点上被卡住. 结束之后脑子瞬间灵光,想出了当时没有迈出的那 ...

  3. linux输入子系统(input subsystem)之evdev.c事件处理过程

    1.代码 input_subsys.drv.c 在linux输入子系统(input subsystem)之按键输入和LED控制的基础上有小改动,input_subsys_test.c不变. input ...

  4. 【repost】JavaScript 事件模型 事件处理机制

    什么是事件? 事件(Event)是JavaScript应用跳动的心脏 ,也是把所有东西粘在一起的胶水.当我们与浏览器中 Web 页面进行某些类型的交互时,事件就发生了.事件可能是用户在某些内容上的点击 ...

  5. 【原】iOS学习之事件处理的原理

    在iOS学习23之事件处理中,小编详细的介绍了事件处理,在这里小编叙述一下它的相关原理 1.UITouch对象 在触摸事件的处理方法中都会有一个存放着UITouch对象的集合,这个参数有什么用呢? ( ...

  6. android事件处理之基于监听

    Android提供了了两种事件处理方式:基于回调和基于监听. 基于监听: 监听涉及事件源,事件,事件监听器.用注册监听器的方法将某个监听器注册到事件源上,就可以对发生在事件源上的时间进行监听. 最简单 ...

  7. Nova PhoneGap框架 第七章 设备事件处理

    我们的框架包含了几种设备事件的处理,目的是为了让我们的程序员更容易的完成代码.这些事件包括:回退键(Android)和横竖屏切换事件. 7.1 Android回退键 首先来说说回退键的事件处理.当用户 ...

  8. 译:DOM2中的高级事件处理(转)

    17.2. DOM2中的高级事件处理(Advanced Event Handling with DOM Level 2)        译自:JavaScript: The Definitive Gu ...

  9. Java基础学习 -- GUI之 事件处理基础

    事件处理可以简单地这么理解,当有一个事件产生,程序要根据这个事件做出响应.比如,我们做了一个可以通过按钮改变背景颜色的窗口,当我们点击按钮时便产生了一个事件,程序会根据这个事件来做出响应,也就是去改变 ...

随机推荐

  1. model.find(options)

    options {Object} 操作选项,会通过 parseOptions 方法解析 return {Promise} 返回单条数据 查询单条数据,返回的数据类型为对象.如果未查询到相关数据,返回值 ...

  2. Java网络编程のTCP/IP

    TCP/IP参考模型和TCP/IP协议 与OSI参考模型相似,TCP/IP参考模型汲取了网络分层的思想,而且对网络的层次做了简化,并在网络各层都提供了完善的协议,这些协议构成了TCP/IP协议集,简称 ...

  3. [转载].NET商业软件源码保护

    列举工作以来遇到的各种类型的软件所采用的代码保护技术,只讲原理不涉及技术细节实现,以避免产生法律问题.有些朋友说直接把代码放在Github开源下载,开源可以促进技术交流与进步,然而值钱的代码都积压在硬 ...

  4. 解决Struts2拦截器的对于参数传递无效问题

    今天做项目时,使用拦截器对用户权限检查.拦截器本身没有问题,可是实现权限拦截,但是传递的参数全部都无效了.搞了很久,由于对拦截器的内部机制不是特别熟悉,所以重新研读了一下Struts2的拦截器.找到了 ...

  5. Windows安装mysql8.0

    一.下载并解压 地址:https://dev.mysql.com/downloads/mysql/ 如下图: 下载解压后 二.创建my.ini文件 在D:\mysql\mysql-8.0.13-win ...

  6. C#应用程序所有已经打开的窗体的集合

    获取所有打开的窗体的集合 Application.OpenForms 获取其中的某个窗体 Application.OpenForms["窗体名"]

  7. cisco和h3c网络设备中一次性打印全部配置信息

    cisco的是全页打印配置信息的命令: #terminal length 0 #show run 华为和h3c的是: >screen-length 0 temporary >display ...

  8. 五,Smarty模板技术/引擎——自定义函数机制

    自建函数是smarty提供的函数,不允许修改,只能被调用: 自定义函数是自己编写函数,注册成为smarty的函数,之后可以被调用: 示例:使用smarty自定义函数的机制,编写一个函数myfun1,通 ...

  9. codis__数据迁移和伸缩容

    数据迁移命令 注意点:是迁移到某个 redis-group 而不是某个redis-servers  实例 伸缩容用法 redis 内存等不够用时 增容 : 增加redis-group, 然后迁移使用上 ...

  10. java集合类学习笔记之HashMap

    1.简述 HashMap是java语言中非常典型的数据结构,也是我们平常用的最多的的集合类之一.它的底层是通过一个单向链表(Node<k,v>)数组(也称之为桶bucket,数组的长度也叫 ...