读jQuery之八 包装事件对象


Posted in Javascript onJune 21, 2011

比如,停止事件冒泡IE用 cancelBubble ,标准浏览器则用 stopPropagation 。
获取事件源对象,IE用 srcElement ,标准浏览器则用 target 诸如此类。
jQuery 对原生事件对象的修复和包装主要使用 jQuery.Event 类和 jQuery.event.fix 方法。

jQuery.Event = function( src ) { 
// Allow instantiation without the 'new' keyword 
if ( !this.preventDefault ) { 
return new jQuery.Event( src ); 
} 
// Event object 
if ( src && src.type ) { 
this.originalEvent = src; 
this.type = src.type; 
// Events bubbling up the document may have been marked as prevented 
// by a handler lower down the tree; reflect the correct value. 
this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false || 
src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse; 
// Event type 
} else { 
this.type = src; 
} 
// timeStamp is buggy for some events on Firefox(#3843) 
// So we won't rely on the native value 
this.timeStamp = jQuery.now(); 
// Mark it as fixed 
this[ jQuery.expando ] = true; 
}; 
function returnFalse() { 
return false; 
} 
function returnTrue() { 
return true; 
} 
// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding 
// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html 
jQuery.Event.prototype = { 
preventDefault: function() { 
this.isDefaultPrevented = returnTrue; 
var e = this.originalEvent; 
if ( !e ) { 
return; 
} 
// if preventDefault exists run it on the original event 
if ( e.preventDefault ) { 
e.preventDefault(); 
// otherwise set the returnValue property of the original event to false (IE) 
} else { 
e.returnValue = false; 
} 
}, 
stopPropagation: function() { 
this.isPropagationStopped = returnTrue; 
var e = this.originalEvent; 
if ( !e ) { 
return; 
} 
// if stopPropagation exists run it on the original event 
if ( e.stopPropagation ) { 
e.stopPropagation(); 
} 
// otherwise set the cancelBubble property of the original event to true (IE) 
e.cancelBubble = true; 
}, 
stopImmediatePropagation: function() { 
this.isImmediatePropagationStopped = returnTrue; 
this.stopPropagation(); 
}, 
isDefaultPrevented: returnFalse, 
isPropagationStopped: returnFalse, 
isImmediatePropagationStopped: returnFalse 
};

jQuery.Event 类主要做了以下工作

1,扩充了 originalEvent 属性,该属性暂存了原生事件对象。
2,修复了 timeStamp ,该属性IE6/7/8不支持,其它支持的各个浏览器中返回值也不同。
3,阻止DOM元素默认行为统一采用 preventDefault
4,停止事件冒泡统一采用 stopPropagation
5,实现或扩充了 DOM3事件 的几个方法:stopImmediatePropagation、isDefaultPrevented、isPropagationStopped、isImmediatePropagationStopped

此外,jQuery.Event的 写类方式 也较独特。它 使用隐藏的new创建对象 。
jQuery.event.fix方法 如下

fix: function( event ) { 
if ( event[ jQuery.expando ] ) { 
return event; 
} 
// store a copy of the original event object 
// and "clone" to set read-only properties 
var originalEvent = event; 
event = jQuery.Event( originalEvent ); 
for ( var i = this.props.length, prop; i; ) { 
prop = this.props[ --i ]; 
event[ prop ] = originalEvent[ prop ]; 
} 
// Fix target property, if necessary 
if ( !event.target ) { 
// Fixes #1925 where srcElement might not be defined either 
event.target = event.srcElement || document; 
} 
// check if target is a textnode (safari) 
if ( event.target.nodeType === 3 ) { 
event.target = event.target.parentNode; 
} 
// Add relatedTarget, if necessary 
if ( !event.relatedTarget && event.fromElement ) { 
event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement; 
} 
// Calculate pageX/Y if missing and clientX/Y available 
if ( event.pageX == null && event.clientX != null ) { 
var doc = document.documentElement, 
body = document.body; 
event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); 
event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); 
} 
// Add which for key events 
if ( event.which == null && (event.charCode != null || event.keyCode != null) ) { 
event.which = event.charCode != null ? event.charCode : event.keyCode; 
} 
// Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs) 
if ( !event.metaKey && event.ctrlKey ) { 
event.metaKey = event.ctrlKey; 
} 
// Add which for click: 1 === left; 2 === middle; 3 === right 
// Note: button is not normalized, so don't use it 
if ( !event.which && event.button !== undefined ) { 
event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) )); 
} 
return event; 
},

它主要做了以下工作
1,event = jQuery.Event( originalEvent ); 该句创建了一个jQuery.Event类的实例对象,该对象修复及扩充上面刚刚提到了。
2, 一个循环将原生事件对象的所有属性拷贝给 1 中的event对象。
for ( var i = this.props.length, prop; i; ) { 
prop = this.props[ --i ]; 
event[ prop ] = originalEvent[ prop ]; 
}

3, 统一事件源对象为 target 。
4, 统一事件相关对象为 relativeTarget 。
5, 扩充了pageX , pageY ,这两个属性首次在Firefox中引入的。不支持该属性的浏览器使用clientX/Y计算得到。
6, 扩充了 which ,使用它获取键盘按键值(keyCode)。这个属性也是在Firefox引入的。
7, 修复了metaKey。
8, 扩充了which,使用它获取鼠标按键值
细心的人可能注意到了,jQuery获取键盘按键值和鼠标按键值都是采用which。它没有向其它属性一样去兼容W3C已有标准 (button )。这一点我在 读jQuery之七 及 各浏览器中鼠标按键值的差异 做了详细分析。
最后,给zChain.js添加包装事件对象的相关代码。
zChain-0.7.1.js
Javascript 相关文章推荐
Javascript实例教程(19) 使用HoTMetal(1)
Dec 23 Javascript
编辑浪子版表单验证类
May 12 Javascript
jquery动态加载js/css文件方法(自写小函数)
Oct 11 Javascript
js实现的页面矩阵图形变换特效
Jan 26 Javascript
Google 地图获取API Key详细教程
Aug 06 Javascript
webix+springmvc session超时跳转登录页面
Oct 30 Javascript
原生javascript上传图片带进度条【实例分享】
Apr 06 Javascript
vue的基本用法与常见指令
Aug 15 Javascript
Node.js dgram模块实现UDP通信示例代码
Sep 26 Javascript
最实用的JS数组函数整理
Dec 05 Javascript
vue组件中的样式属性scoped实例详解
Oct 30 Javascript
详解JavaScript 事件流
Sep 02 Javascript
读jQuery之七 判断点击了鼠标哪个键的代码
Jun 21 #Javascript
读jQuery之六 缓存数据功能介绍
Jun 21 #Javascript
将HTMLCollection/NodeList/伪数组转换成数组的实现方法
Jun 20 #Javascript
读jQuery之五(取DOM元素)
Jun 20 #Javascript
读jQuery之四(优雅的迭代)
Jun 20 #Javascript
火狐4、谷歌12不支持Jquery Validator的解决方法分享
Jun 20 #Javascript
合并table相同单元格的jquery插件分享(很精简)
Jun 20 #Javascript
You might like
延长phpmyadmin登录时间的方法
2011/02/06 PHP
简单的方法让你的后台登录更加安全(php中加session验证)
2012/08/22 PHP
PHP中数组的分组排序实例
2014/06/01 PHP
php中ftp_chdir与ftp_cdup函数用法
2014/11/18 PHP
PHP获取POST数据的几种方法汇总
2015/03/03 PHP
php通过header发送自定义数据方法
2018/01/18 PHP
脚本吧 - 幻宇工作室用到js,超强推荐base.js
2006/12/23 Javascript
js的with语句使用方法
2007/09/21 Javascript
子窗口、父窗口和Silverlight之间的相互调用
2010/08/16 Javascript
jQuery中replaceAll()方法用法实例
2015/01/16 Javascript
javascript自动生成包含数字与字符的随机字符串
2015/02/09 Javascript
基于jQuery实现的向下滑动二级菜单效果代码
2015/08/31 Javascript
浅析jQuery Ajax通用js封装
2016/06/22 Javascript
JavaScript每天必学之基础知识
2016/09/17 Javascript
javascript汉字拼音互转的简单实例
2016/10/09 Javascript
JS DOMReady事件的六种实现方法总结
2016/11/23 Javascript
Bootstrap源码解读排版(1)
2016/12/23 Javascript
在js中做数字字符串补0(js补零)
2017/03/25 Javascript
NodeJs操作MongoDB教程之分页功能以及常见问题
2019/04/09 NodeJs
vue服务端渲染操作简单入门实例分析
2019/08/28 Javascript
微信小程序国际化探索实现(附源码地址)
2020/05/20 Javascript
开始着手第一个Django项目
2015/07/15 Python
Python 3.x读写csv文件中数字的方法示例
2017/08/29 Python
Python 3.8中实现functools.cached_property功能
2019/05/29 Python
linux环境下Django的安装配置详解
2019/07/22 Python
Django+Uwsgi+Nginx如何实现生产环境部署
2020/07/31 Python
无需压缩软件,用python帮你操作压缩包
2020/08/17 Python
html5标记文字_动力节点Java学院整理
2017/07/11 HTML / CSS
美国酒店控股公司:Choice Hotels
2018/06/15 全球购物
意大利咖啡、浓缩咖啡和浓缩咖啡机:illy caffe
2019/03/20 全球购物
开学典礼演讲稿
2014/05/23 职场文书
全国优秀教师事迹材料
2014/08/26 职场文书
利用Selenium添加cookie实现自动登录的示例代码(fofa)
2021/05/08 Python
教你用python实现12306余票查询
2021/06/30 Python
SQL实现LeetCode(180.连续的数字)
2021/08/04 MySQL
Nginx HTTP跳转至HTTPS
2022/05/15 Servers