第二十六课:jQuery对事件对象的修复
因为原生的event对象,在不同浏览器下,有不同的属性和方法,因此需要用jQuery进行兼容。
jQuery在这里分两步走,首先创建一个伪事件类jQuery.Event(jQuery里面自定义的事件类),这个事件类会统一处理事件对象的兼容性问题,比如:stopPropagation,preventDefault方法。然后通过jQuery.event.fix方法,针对不同的事件类型修复特定的属性。比如:mousewheel,keydown等事件类型。
jQuery.Event = function(src, props){
if(!(this instanceof jQuery.Event)){ //如果不是new jQuery.Event(),就返回一个new出来的jQuery.Event对象
return new jQuery.Event(src,props);
}
if(src && src.type){ //如果传进来的src有type属性,也就是event对象
this.originalEvent = src; //存储原始事件,也就是event事件对象
this.type = src.type;
this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false ||src.getPregentDefault && src.getPreventDefault()) ? returntrue : return false; //如果传进来的event对象是阻止默认事件的,那么自定义事件(jQuery.Event)的isDefaultPrevented 属性为returntrue。
}
else{ //如果传进来的src没有type属性,也就是不是event对象而是事件类型,比如click,就把src当做此事件的type属性值,也就是这个事件类的事件类型就是src
this.type = src;
}
if(props){
jQuery.extend(this,props); //如果传入了一个对象,就复制它的属性到自定义事件对象中。
}
this.timeStamp = src && src.timeStamp || jQuery.now(); //有些浏览器下,事件对象有timeStamp属性,没有的,就用now方法,得到当前日期的毫秒数
this[jQuery.expando] = true; //标识这个自定义事件对象已经修正过
}
jQuery.Event.prototype = {
preventDefault : function(){
this.isDefaultPrevented = returnTrue;
var e = this.originalEvent;
if(!e){ //如果传入的不是event对象,就没有阻止事件默认行为。
return;
}
if(e.preventDefault){
e.preventDefault();
}else{
e.returnValue = false; // IE下阻止事件默认行为的代码
}
},
stopPropagation: function(){
this.isPropagationStopped = returnTrue;
var e = this.originalEvent;
if(!e){ //如果传入的不是event对象,就不用阻止冒泡行为。
return;
}
if(e.stopPropagation){
e.stopPropagation();
}
e.cancelBubble= true; // IE下阻止事件冒泡的代码
},
stopImmediatePropagation: function(){
this.isImmediatePropagationStopped = returnTrue;
this.stopPropagation();
},
isDefaultPrevented : returnFalse,
isPropagationStopped : returnFalse,
isImmediatePropagationStopped : returnFalse
}
jQuery.event.fix也很简单,它把大部分逻辑分担给其他钩子对象了,比如:mouseHooks处理mouse事件对象的不同属性,keyHooks处理键盘事件对象的不同属性。
fix = function(event){
if(event[jQuery.expando]){ //如果事件对象已经修正了,那么就直接返回。
return event;
}
var i,prop,originalEvent = event,fixHook = jQuery.event.fixHooks[event.type] || {}, //查找此事件类型是否有相对应的钩子对象。
copy = fixHook.props ? this.props.concat(fixHooks.props) : this.props; //如果此钩子对象有相应的属性集合,就把这些属性集合合并到当前this.props属性集合中
event = jQuery.Event(originalEvent); //得到jQuery自定义事件对象
for(i=copy.length;i;){
prop = copy[--i]; //得到此事件对象的属性名
event[prop] = originalEvent[prop]; //把原始对象的属性值赋给此jQuery事件对象的属性名
}
if(!event.target){ //IE6-8下是srcElement
event.target = originalEvent.srcElement || document;
}
if(event.target.nodeType === 3){ //文本节点不能作为事件目标元素,在火狐和safari下
event.target = event.target.parentNode;
}
event.metaKey = !!event.metaKey;//metaKey事件属性可返回一个布尔值,指示当事件发生时,"meta" 键是否被按下并保持住。大多数键盘上并不存在Meta键,该键存在于MIT计算机、Mac计算机或Sun公司的一些计算机键盘上。IE6-8下不支持。
return fixHook.filter ? fixHook.filter(event,originalEvent) : event; //此事件相对应的钩子对象是否有filter方法,如果有就证明此事件对象需要进行修复处理。因此执行钩子对象的filter方法修复事件对象,然后返回这个修复后的event。
}
jQuery只修复了键盘事件和鼠标事件。
键盘事件的重点在于修复keyCode,不过W3C已经规定which才是标准属性,因此兼容性写法是:
if(event.which == null){ //如果不支持W3C的which属性。就进行修复。
event.which = event.charCode !=null ? event.charCode : event.keyCode; //先取事件对象的charCode属性值,如果这属性值不存在,就取event的keyCode属性值
}
鼠标事件的重点是修复pageX/pageY,relatedTarget与用于左中右键的which属性。
clientX clientY 为事件触发时鼠标在当前浏览器可视区的坐标
screenX screenY 为事件触发时鼠标在屏幕的坐标
pageX pageY 为事件触发时鼠标在整个document的坐标,IE6-8不支持。
offsetX offsetY 为事件触发时鼠标在事件源元素的坐标,不过元素的区域有很多计算方式,按规范来说,参考点是padding围成的区域(不包括滚动条和边框)的左上角。
layerX layerY 为事件发生时鼠标相当于事件源元素的offsetParent的坐标,IE6-8不支持。
x y 是IE的layerX,layerY。但是IE6-8的offsetParent存在bug,比如td元素的offsetParent总是table,不推荐使用这两个属性。
我们修复IE6-8下的pageX和pageY:
e.pageX = e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft);
e.pageY = e.clientY + (document.documentElement.scrollTop || document.body.scrollTop);
IE兼容模式下,窗口滚动条是出现在body中的,标准模式下,窗口滚动条出现在html。webkit下,窗口滚动条出现在body中,火狐和Opera的滚动条在html中。当窗口滚动条出现在body中时,document.body.scrollLeft是我们想要的值,而document.documentElement.scrollLeft为0,反之亦然。
在IE6-7标准模式以及IE全系列的怪异模式下,页面左上角存在2px的偏移值(表现在document.body.clientLeft,document.body.clientTop),这会导致我们在IE下取到的pageX和pageY比其他的浏览器大2px。
在IE下触发标准模式很简单,使用<!DOCTYPE HTML>在页面最前面就行了,它的前面不能有任何字符。切换成怪异模式有以下几种方法:
(1)在最前面加上非法的标签,如<ddd></ddd>
(2)在最前面加上一段文本,如ddddddd
(3)在IE6下,在最前面加上XML声明,如:<?xml version="1.0" encoding="utf-8"?>。
一般使用第一个方案。
IE在怪异模式下,页面显示用的顶级容器是body,2px 的偏移在body中表现,我们可以通过在body{ border:0},消除这个2px的偏移量。而且也可以使用html{border:0}消除。意思就是在怪异模式下,IE可以通过在body或html中设置boder:0消除2px的偏移。
那么,标准模式下,IE6-7呢?标准模式下,IE6可以通过以上方式消除2px的偏移,但是IE7不行,所以要兼容所有浏览器,就不能使用修改样式的方式。因此完美方案:
if(event.pageX ==null && event.clientX !=null){ //处理鼠标事件的
var doc = event.target.ownerDocument || document;
var box = document.compatMode == "BackCompat" ? doc.body : doc.documentElement; //文档模式是怪异模式,就使用body
event.pageX = event.clientX + (box && box.scrollLeft || 0) - (box && box.clientLeft || 0);
event.pageY = event.clientY + (box && box.scrollTop || 0) - (box && box.clientTop || 0);
}
如果不是html文档,而是xml或svg文档,就没有scrollLeft和clientLeft属性。
加油!
第二十六课:jQuery对事件对象的修复的更多相关文章
- NeHe OpenGL教程 第二十六课:反射
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- 第一百七十节,jQuery,事件对象,event 对象,默认行为,冒泡
jQuery,事件对象,event 对象,默认行为,冒泡 学习要点: 1.事件对象 2.冒泡和默认行为 JavaScript 在事件处理函数中默认传递了 event 对象,也就是事件对象.但由于浏览器 ...
- 第二十二课:js事件原理以及addEvent.js的详解
再看这篇博客之前,希望你已经对js高级程序编程一书中的事件模块进行了详读,不然我只能呵呵了. document.createEventObject,在IE下创建事件对象event. elem.fire ...
- 第二十六篇 jQuery 学习8 遍历-父亲兄弟子孙元素
jQuery 学习8 遍历-父亲兄弟子孙元素 jQuery遍历,可以理解为“移动”,使用“移动”还获取其他的元素. 什么意思呢?老师举一个例子: 班上30位同学,我是新来负责教这个班学生的老师 ...
- javascript第十六课:动态注册事件
直接给dom元素添加动态事件,如: document.getelementbyid('#id').onclick=function(){ 方法体! };
- 第二十六课 典型问题分析(Bugfix)
问题1: glibc中的strdup实现如下: 没有对参数s进行空指针判断. 我们的Exception.cpp中应做改进: 在第12行进行判断空指针操作. 问题2: t1在析构时会抛出异常,我们在re ...
- python第三十六课——1.可迭代对象
1.可迭代对象: 满足前提: 只要能被循环操作的对象,就可以可迭代对象 举例: str.list.tuple.set.dict.range.generator... 高效的检测一个对象是否是可迭代对象 ...
- python第二十六课——装饰器
装饰器是闭包的一种使用场景: python中的装饰器在定义上需要传入一个函数对象, 在此函数执行之前或者之后都可以追加其它的操作, 这样做的好处是,在不改变源码(原本业务逻辑的)同时,进行功能的扩展: ...
- Spring入门第二十六课
Spring中的事务管理 事务简介 事务管理是企业级应用程序开发中必不可少的技术,用来确保数据的完整性和一致性. 事务就是一系列的动作,他们被当做一个单独的工作单元,这些动作要么全部完成,要么全部不起 ...
随机推荐
- 利用Windows自带的Certutil查看文件MD5
当遇到需要对比两个文件是否一致时,可以使用下面的命令来显示文件的MD5, 然后对比两个文件的MD5码. certutil -hashfile <filename> MD5 命令的相关帮助信 ...
- MySQL在创建相同表结构时as和like 使用的区别
1.MySQL的复制相同表结构方法: 1)create table table_name as select * from table1 where 1=2 (或者limit 0): 2) crea ...
- phpcms v9 下拉菜单 二级 三级子栏目调用方法
很多网站的导航栏可以实现下拉二级菜单,三级菜单等效果,今天我们就来分享phpcms v9 支持下拉菜单的方法,可以支持无限子栏目调用,具体写法如下: <ul> {pc:content ac ...
- uva 10562 undraw the trees(烂题) ——yhx
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAABB4AAAM9CAYAAAA7ObAlAAAgAElEQVR4nOyd25GsupKGywVswAV8wA ...
- 深入理解UIApplication和ios程序启动过程
在深入理解UIApplication前我们先了解ios程序的启动过程: UIApplication类在ios里面为app的管理和协调提供一个集中的点,每一个app有一个UIApplication的实例 ...
- web前端笔试题总结
em和rem的区别: 浏览器的默认字体高度是16px,1em=16px:大小可以自己设置调整,并且默认集成父级容器中文本的大小. rem是CSS3中新增的属性,默认情况下是文本尺寸的大小,不同的是它集 ...
- opencv3.1 + opencv_contrib编译记事(win7下)
折腾了好几天,终于把opencv3.1加上一个额外的包opencv_contrib编译好了.(总体来说编译opencv就是填坑!!!) 最后我编译成功的是mingw版本的.也就是结合了Qt4.7+cm ...
- 推荐——Monkey《大话 app 测试——Android、iOS 应用测试指南》
<大话移动——Android与iOS应用测试指南> 京东可以预购啦!http://item.jd.com/11495028.html 当当网:http://product.dangdang ...
- Zero
Zero是我的极品现任BOSS曾用过的QQ昵称.那时候,我正跟京姑娘闹七年之痒,甩她而去赋闲在老家.Zero通过朋友介绍,看了我几篇零散的博客,就给我打电话,让我过来聊聊.本来我跟京姑娘也没有大矛盾, ...
- UVALive 6181
模拟题,注意细节.. #include <iostream> #include<stdio.h> #include<math.h> #include<stri ...