先看看下面一道题目,请评价以下代码并给出改进意见:

if (window.addEventListener) {//标准浏览器
var addListener = function(el, type, listener, useCapture) {
el.addEventListener(type, listener, useCapture);
};
} else if (document.all) {//IE
addListener = function(el, type, listener) {
el.attachEvent("on" + type, function() {
listener.apply(el);
});
}
}

1)不应该在if和else语句中声明addListener函数,应该先声明;

2)不需要使用window.addEventListener或document.all来进行检测浏览器,应该使用能力检测;

3)attachEvent在IE中有this指向问题,会指向window,虽然上面的代码做了指向处理,但是匿名函数不能做detachEvent解绑

改进后的代码稍后加上。

一、冒泡与捕获

使用过addEventListener方法的会发现最后一个参数“useCapture”,用于控制是捕获还是冒泡。

何为冒泡、捕获,请看下面的例子:查看在线代码,在线代码中用了三层。

<div id="click1">
<div id="click2">事件</div>
</div>

1)Netscape主张元素1的事件首先发生,这种事件发生顺序被称为捕获型,如下图所示:

               | |
---------------| |-----------------
| click1 | | |
| -----------| |----------- |
| |click2 \ / | |
| ------------------------- |
| Event CAPTURING |
-----------------------------------

2)微软则保持元素2具有优先权,这种事件顺序被称为冒泡型,如下图所示:

               / \
---------------| |-----------------
| click1 | | |
| -----------| |----------- |
| |click2 | | | |
| ------------------------- |
| Event BUBBLING |
-----------------------------------

3)W3C选择了一个择中的方案。任何发生在w3c事件模型中的事件,首是进入捕获阶段,直到达到目标元素,再进入冒泡阶段,如下图所示:

               | |  / \
---------------| |--| |------------
| click1 | | | | |
| -----------| |--| |------ |
| |click2 \ / | | | |
| ------------------------- |
| W3C event model |
-----------------------------------

4)阻止冒泡,很多时候是不想触发父级的相同事件的,那么就需要阻止这种行为。

W3C方:event.stopPropagation()。(chrome、firefox、safrai等)

IE方:event.cancelBubble设置为true。

经过我的在线测试,stopPropagation这个方法不能阻止捕获。

这里顺带说下阻止默认事件的方法,何为默认事件?就比如a标签设置了href,就会做跳转,这里阻止它跳转。

W3C方:event.preventDefault(),但只有event的cancelable属性为true时才能使用。

IE方:event.returnValue设置为false。

二、事件系统

浏览器提供了3种层次的API。

1)最原始的是写在元素标签内

2)以el.onXXX=function绑定的方式,通称为DOM0事件系统。

3)一个元素的同一类型事件可以绑定多个回调,通称为DOM2事件系统。

IE与W3C依旧不同,语法如下:

序号  操作与对象 IE方 W3C方

1

绑定事件

el.attachEvent("on"+type, callback) el.addEventListener(type,callback,[useCapture])

2

卸载事件

el.detachEvent("on"+type,callback) el.removeEventListener(type,callback,[useCapture])
3 创建事件 document.createEventObject()

document.createEvent(types) 创建事件(过时)

event.initEvent() 初始化事件(过时)

new Event(types)

4

派发事件

el.fireEvent(type,event) el.dispatchEvent(event)
5 event属性 srcElement:等于target,默认目标

currentTarget:其事件处理程序当前正处理事件的元素

target:事件的目标

6 event方法

returnValue:等于preventDefault()

cancelBubble:设为true等于stopPropagation()

preventDefault():阻止默认行为

stopPropagation():阻止冒泡

7

type

被触发的事件类型,需要“on”前缀 被触发的事件类型

8

事件执行顺序

与添加顺序相反 与添加顺序一致
9

匿名函数

无法移除 无法移除

10

this

window 当前绑定的元素

注意第8点,在测试代码中,我绑定了两个相同的“click”事件, 查看在线完整代码。

var func1 = function(e) {
alert(1); //测试执行顺序
};
var func2 = function(e) {
alert(2);
};
var type = 'click';
bind(ele, type, func1);
bind(ele, type, func2);

在IE中先弹出2,再弹出1。而在chrome中先弹出1,再弹出2。

注意上面的第9点和第10点,上面那道题目中要解决的就是这个问题。下面的代码是个片段,查看在线完整代码。

var bind = function(ele, type, callback) {
if (!ele[type + "event"]) {
ele[type + "event"] = {}; //声明一个空对象,缓存事件
}
var name = callback.toString();
if (!ele[type + "event"][name]) {
var handler = function(event) {
//可以做更多event封装操作
var ev = event || window.event;
callback.call(ele, ev);
};
ele[type + "event"][name] = handler; //做个临时变量
} if (ele.addEventListener) {
ele.addEventListener(type, handler, false);
} else if (ele.attachEvent) {
ele.attachEvent('on' + type, handler);
}
}
var unbind = function(ele, type, callback) {
var handler = ele[type + "event"][callback.toString()]; //读取临时变量
if (ele.removeEventListener) {
ele.removeEventListener(type, handler);
} else if (ele.detachEvent) {
ele.detachEvent('on' + type, handler);
}
}

上面的代码还比较粗糙,仅仅是用于演示一下。方法有很多,自己可以揣摩。

我看到网上有人直接不用attachEvent,将相应的事件保存在一个数组中,当detachEvent的时候做splice数组的操作。

大家也可以参考下一些成熟的类库,例如jQuery1.8.3版本,2642行的event.add封装,2757行的event.remove封装,3485行的on封装。

也可以参考Dean Wdwards写的addEvent方法,这是Prototype时代早期出现的一个事件系统,jQuery事件系统的源头。

参考资料:

前端事件系统(一)

JavaScript要点归档:事件

生动详细解释javascript的冒泡和捕获

解决attachEvent中this指向问题

创建和触发 events

JavaScript中事件处理的更多相关文章

  1. [转]理解JavaScript中的事件处理

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

  2. 理解JavaScript中的事件处理

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

  3. 理解JavaScript中的事件处理 阻止冒泡event.stopPropagation();

    原文地址:http://www.cnblogs.com/binyong/articles/1750263.html 这篇文章对于了解Javascript的事件处理机制非常好,将它全文转载于此,以备不时 ...

  4. 详解JavaScript中的事件处理

    在漫长的演变史,我们已经告别了内嵌式的事件处理方式(直接将事件处理器放在HTML元素之内来使用),今天的事件,它已是DOM的重要组成部分,遗憾的是,IE继续保留它最早在IE4.0中实现的事件模型,以后 ...

  5. 关于javascript中的this关键字

    this是非常强大的一个关键字,但是如果你不了解它,可能很难正确的使用它. 下面我解释一下如果在事件处理中使用this. 首先我们讨论一下下面这个函数中的this关联到什么. function doS ...

  6. 理解JavaScript中的作用域和上下文

    JavaScript对于作用域(Scope)和上下文(Context)的实现是这门语言的一个非常独到的地方,部分归功于其独特的灵活性. 函数可以接收不同的的上下文和作用域.这些概念为JavaScrip ...

  7. javascript 中的事件机制

    1.javascript中的事件. 事件流 javascript中的事件是以一种流的形式存在的. 一个事件会也有多个元素同时响应. 有时候这不是我们想要的效果, 我们只是需要某个特定的元素相应我们的绑 ...

  8. 20个优秀的 JavaScript 键盘事件处理库

    键盘事件是 Web 开发中最常用的事件之一,通过对键盘事件的捕获和处理可以提高网站的易用性和交互体验.下面,我们向大家介绍收集的20款优秀的 JavaScript 键盘事件处理库,帮助开发人员轻松处理 ...

  9. JavaScript中的this关键字

    在JavaScript中,函数的this关键字的行为与其他语言相比有很多不同.在JavaScript的严格模式和非严格模式下也略有区别. 在绝大多数情况下,函数的调用方式决定了this的值.this不 ...

随机推荐

  1. 【分享】标准springMVC+mybatis项目maven搭建最精简教程

    文章由来:公司有个实习同学需要做毕业设计,不会搭建环境,我就代劳了,顺便分享给刚入门的小伙伴,我是自学的JAVA,所以我懂的.... (大图直接观看显示很模糊,请在图片上点击右键然后在新窗口打开看) ...

  2. 透过WinDBG的视角看String

    摘要 : 最近在博客园里面看到有人在讨论 C# String的一些特性. 大部分情况下是从CODING的角度来讨论String. 本人觉得非常好奇, 在运行时态, String是如何与这些特性联系上的 ...

  3. tomcat开发远程调试端口以及利用eclipse进行远程调试

    一.tomcat开发远程调试端口 方法1 WIN系统 在catalina.bat里:  SET CATALINA_OPTS=-server -Xdebug -Xnoagent -Djava.compi ...

  4. 阿里云学生优惠Windows Server 2012 R2安装IIS,ftp等组件,绑定服务器域名,域名解析到服务器,域名备案,以及安装期间错误的解决方案

     前言: 这几天终于还是按耐不住买了一个月阿里云的学生优惠.只要是学生,在学信网上注册过,并且支付宝实名认证,就可以用9块9的价格买阿里云的云服务ECS.确实是相当的优惠. 我买的是Windows S ...

  5. 读书笔记汇总 - SQL必知必会(第4版)

    本系列记录并分享学习SQL的过程,主要内容为SQL的基础概念及练习过程. 书目信息 中文名:<SQL必知必会(第4版)> 英文名:<Sams Teach Yourself SQL i ...

  6. 【云知道】究极秒杀Loadrunner乱码

    Loadrunner乱码一击必杀 之前有介绍一些简单的针对Loadrunner脚本或者调试输出内容中乱码的一些设置,但是并没能完全解决一些小伙伴的问题,因为那些设置实在能力有限,还是有很多做不到的事情 ...

  7. Newtonsoft.Json设置类的属性不序列化

    参考页面: http://www.yuanjiaocheng.net/webapi/parameter-binding.html http://www.yuanjiaocheng.net/webapi ...

  8. 【夯实PHP基础】UML序列图总结

    原文地址 序列图主要用于展示对象之间交互的顺序. 序列图将交互关系表示为一个二维图.纵向是时间轴,时间沿竖线向下延伸.横向轴代表了在协作中各独立对象的类元角色.类元角色用生命线表示.当对象存在时,角色 ...

  9. [OC] NSURLSession

    有的程序员老了,还没听过NSURLSession 有的程序员还嫩,没用过NSURLConnection 有的程序员很单纯,他只知道AFN. NSURLConnection在iOS9被宣布弃用,NSUR ...

  10. 敏捷软件开发VS传统软件工程

    敏捷软件开发:又称敏捷开发,是一种从1990年代开始逐渐引起广泛关注的一些新兴软件开发方法,是一种应对快速变化的需求的一种软件开发能力. 与传统软件工程相比,它们的具体名称.理念.过程.术语都不尽相同 ...