JavaScript中事件处理
先看看下面一道题目,请评价以下代码并给出改进意见:
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中的事件处理
什么是事件? 事件(Event)是JavaScript应用跳动的心脏 ,也是把所有东西粘在一起的胶水.当我们与浏览器中 Web 页面进行某些类型的交互时,事件就发生了.事件可能是用户在某些内容上的点击 ...
- 理解JavaScript中的事件处理
什么是事件? 事件(Event)是JavaScript应用跳动的心脏 ,也是把所有东西粘在一起的胶水.当我们与浏览器中 Web 页面进行某些类型的交互时,事件就发生了.事件可能是用户在某些内容上的点击 ...
- 理解JavaScript中的事件处理 阻止冒泡event.stopPropagation();
原文地址:http://www.cnblogs.com/binyong/articles/1750263.html 这篇文章对于了解Javascript的事件处理机制非常好,将它全文转载于此,以备不时 ...
- 详解JavaScript中的事件处理
在漫长的演变史,我们已经告别了内嵌式的事件处理方式(直接将事件处理器放在HTML元素之内来使用),今天的事件,它已是DOM的重要组成部分,遗憾的是,IE继续保留它最早在IE4.0中实现的事件模型,以后 ...
- 关于javascript中的this关键字
this是非常强大的一个关键字,但是如果你不了解它,可能很难正确的使用它. 下面我解释一下如果在事件处理中使用this. 首先我们讨论一下下面这个函数中的this关联到什么. function doS ...
- 理解JavaScript中的作用域和上下文
JavaScript对于作用域(Scope)和上下文(Context)的实现是这门语言的一个非常独到的地方,部分归功于其独特的灵活性. 函数可以接收不同的的上下文和作用域.这些概念为JavaScrip ...
- javascript 中的事件机制
1.javascript中的事件. 事件流 javascript中的事件是以一种流的形式存在的. 一个事件会也有多个元素同时响应. 有时候这不是我们想要的效果, 我们只是需要某个特定的元素相应我们的绑 ...
- 20个优秀的 JavaScript 键盘事件处理库
键盘事件是 Web 开发中最常用的事件之一,通过对键盘事件的捕获和处理可以提高网站的易用性和交互体验.下面,我们向大家介绍收集的20款优秀的 JavaScript 键盘事件处理库,帮助开发人员轻松处理 ...
- JavaScript中的this关键字
在JavaScript中,函数的this关键字的行为与其他语言相比有很多不同.在JavaScript的严格模式和非严格模式下也略有区别. 在绝大多数情况下,函数的调用方式决定了this的值.this不 ...
随机推荐
- Fis3前端工程化之项目实战
Fis3项目 项目目录结构: E:. │ .gitignore │ fis-conf.js │ index.html │ package.json │ README.md │ ├─material │ ...
- MVVM TextBox的键盘事件
MVVM下RichTextBox的键盘回车事件设置为发送,不是回车 xmlns:i="http://schemas.microsoft.com/expression/2010/interac ...
- 使用C/C++写Python模块
最近看开源项目时学习了一下用C/C++写python模块,顺便把学习进行一下总结,废话少说直接开始: 环境:windows.python2.78.VS2010或MingW 1 创建VC工程 (1) 打 ...
- MySQL 系列(三)你不知道的 视图、触发器、存储过程、函数、事务、索引、语句
第一篇:MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:MySQL 系列(二) 你不知道的数据库操作 第三篇:MySQL 系列(三)你不知道的 视图.触发器.存储过程.函数 ...
- 我这么玩Web Api(一):帮助页面或用户手册(Microsoft and Swashbuckle Help Page)
前言 你需要为客户编写Api调用手册?你需要测试你的Api接口?你需要和前端进行接口对接?那么这篇文章应该可以帮到你.本文将介绍创建Web Api 帮助文档页面的两种方式,Microsoft Help ...
- Redis简单案例(二) 网站最近的访问用户
我们有时会在网站中看到最后的访问用户.最近的活跃用户等等诸如此类的一些信息.本文就以最后的访问用户为例, 用Redis来实现这个小功能.在这之前,我们可以先简单了解一下在oracle.sqlserve ...
- C# 用SoapUI调试WCF服务接口(WCF中包含用户名密码的验证)
问题描述: 一般调试wcf程序可以直接建一个单元测试,直接调接口. 但是,这次,我还要测试在接口内的代码中看接收到的用户名密码是否正确,所以,单一的直接调用接口方法行不通, 然后就想办法通过soapU ...
- 高德地图api实现地址和经纬度的转换(python)
利用高德地图web服务api实现地理/逆地址编码 api使用具体方法请查看官方文档 文档网址:http://lbs.amap.com/api/webservice/guide/api/georegeo ...
- 注释生成Api文档
1.开发背景 最近一直在写dubbo接口,以前总是用word文档写接口描述然后发给别人.现在太多了,而且跟别人对接联调的人家急着用,根本没时间去写word文档.那就想想怎么用doc文档注释自动生成接口 ...
- Mysql基础代码(不断完善中)
Mysql基础代码,不断完善中~ /* 启动MySQL */ net start mysql /* 连接与断开服务器 */ mysql -h 地址 -P 端口 -u 用户名 -p 密码 /* 跳过权限 ...