- 浏览: 10795 次
- 性别:
- 来自: 广州
最近访客 更多访客>>
文章分类
最新评论
-
leaow567:
写的好,1.8里面有少些变化
jQuery1.7系列三: jQuery延迟列表(Deferred)
声明:写博客,是对自身知识的一种总结,也是一种分享,但由于作者本人水平有限,难免会有一些地方说得不对,还请大家友善 指出,或致电:tianzhen.chen0509@gmail.com
关注:国内开源jQuery-UI组件库:Operamasks-UI
jQuery版本:v1.7.1
jQuery1.7系列四: 事件
一. 有感而发
处理过前端脚本事件的朋友都清楚,各浏览器在处理DOM上的事件的不一致性让人烦不胜烦。而为了提供一致的访问接口,jQuery作者提供了一套犀利的解决方案,这种思想是值得我们借鉴和学习的。
二.传统事件处理蔽端
多说无益,我们直接从以下例子来看看浏览器间在事件处理方面的一些不一致性。
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script type="text/javascript" src="jquery-1.7.1.js"></script> <script> function f1(event){ //IE上事件对象从window.event获取,其它浏览器一般会以参数传进来 event = event || window.event; alert(event.pageX); } function bind(){ var btn = document.getElementById("btn"); if(document.attachEvent){ btn.attachEvent("onclick" , f1); btn.attachEvent("onclick" , f1); }else if(document.addEventListener){ btn.addEventListener("click" , f1 , false); btn.addEventListener("click" , f1 , false); } } /**测试结果: **在火狐上,弹出两个窗口,分别打印出 "original click." "50" **在IE9上,弹出两个窗口,分别打印出 "original click." "undefined" **在IE8上,弹出三个窗口,分别打印出 "original click." "undefined" "undefined"(两个undefined,你没有看错) */ </script> </head> <body onload="bind()"> <input id="btn" type="button" value="click me" onclick="alert('original click.');"/> </body> </html>
就上面这个非常简单的例子,我们就可以看出几个浏览器间事件处理会出现不一致的地方
1. 事件的绑定方式不同
2. 获取event对象的方式不同
3. event对象中的数据不完全相同
4. 对重复添加同一处理函数的处理方式不同,有人叠加有人忽略
还有一些例子没有体现出来,比如不可以添加两个处理事件,后添加的会覆盖前面的;阻止事件冒泡的方式和阻止其默认行为;还有什么,等你来挖掘。
既然有如此多的不一致性,jQuery作者当然想办法要进行屏蔽了,而大师的处理方式将是本文章要探讨的内容。
三.jQuery的事件处理方式
3.1 自己实现事件处理
事件绑定方式不同,这个解决不难,只要不同浏览器采用不同绑定方式,像第二部分的例子一样就行了。但如何处理类似不可以添加多个处理函数这种局限?我们自己来试着解决一下:
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script type="text/javascript" src="jquery-1.7.1.js"></script> <script> window.guid = 0;//标记各个不同的DOM节点 var cache = {};//缓存对象,用于存储事件处理器 function bind(elem , type , handler){ //给dom节点添加一个唯一属性,用于标识该 dom节点 if(!elem["guid"]){ elem["guid"] = ++window.guid; } var events = cache[elem["guid"]]; if(!events){ //初始化dom节点的缓存数据对象 cache[elem["guid"]] = events = {}; events[type] = events[type] || []; //同一个dom节点只注册一次事件,那就是eventHandle,然后在eventHandle中调用dispatch进行分发 if(document.attachEvent){ elem.attachEvent("on"+type , eventHandle); }else if(document.addEventListener){ elem.addEventListener(type , eventHandle , false); } } events[type].push(handler); } function dispatch(elem , event){ var events = window.cache[elem["guid"]], ret; if(!events){ return ; } var handlers = events[event.type]; for(var i=0,len=handlers.length; i<len; i++){ //event作为参数传递过去 ret = handlers[i].call(elem , event); } if(ret != undefined){ if ( ret === false ) { event.preventDefault(); event.stopPropagation(); event.cancleBubble = true; event.returnValue = false; } } } function eventHandle(event){ event = event || window.event; dispatch(this , event); } function test(){ var btn = document.getElementById("btn"); bind(btn , "click" , function(){alert("click1");}); //当下边改为bind(btn , "click" , function(){alert("click2");return false});时, //点击按钮不会显示 "wrapper",因为取消冒泡了 bind(btn , "click" , function(){alert("click2");}); var wrapper = document.getElementById("wrapper"); bind(wrapper , "click" , function(){alert("wrapper");}); } //点击按钮后,弹出窗口依次显示 : click1 click2 wrapper </script> </head> <body onload="test()"> <div id="wrapper"> <input id="btn" type="button" value="click me"/> </div> </body> </html>
以上代码虽然不是很多,但却是jQuery处理事件的一个小缩影。我们 统一给dom节点注册了一个事件eventHandle,也就是说不管该dom触发什么类型的事件,一定会执行eventHandle,然后在 eventHandle中再调用dispatch进行分发,也就是根据事件类型在缓存中查找相应的处理器。这样可以得到很多好处,最明显的就是可以添加多 个处理器了,以后用户再也不用怕兼容性问题了,我们全部都隐藏在了内部实现中。当绑定完后,我们可以看下缓存是怎样的。
如果看懂了以上这个 event 的示例,那么jQuery关于事件的处理最核心的东西你已经知道了,接下来我们来看下jQuery的做法。
3.2 jQuery的事件处理
先来看个流程图:
上图是一个处理流程图,jQuery分几步来处理:
1. 给每个dom节点注册一个唯一的处理器(eventHandle)
2. 不管该dom触发了什么事件,都会执行eventHandle, 然后eventHandle调用dispatch进行事件的真正处理
3. dispatch进行事件的修正,用jQuery自定义的事件类型来包装原生的event对象,这样提供统一的访问接口,如event.target在任何浏览器下表示触发事件的源dom节点。
4. 在jQuery公用缓存中获取该dom节点的处理器数据,由于委托机制的存在(稍后再讲),所以先获取此节点的委托处理器列表。
5. 把此节点的委托处理器列表与本节点本身的处理器列表进行合并,形成最终的处理器列表。
6. 执行最终的处理器列表,并即时处理取消冒泡和阻止浏览器默认行为。
看到这里,发现大体思想还是比较简单的吧,那我们再来深入一些细节,首先看看当绑定事件后缓存的存储情况怎样?
Html代码
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script type="text/javascript" src="jquery-1.7.1.js"></script> <script> $(function($){ $("#btn").bind("click" , function(){alert("f1");}) .bind("click" , function(){alert("f2");}); }); //当点击按钮后弹出窗口依次显示 f1 f2 </script> </head> <body> <div id="wrapper"> <input id="btn" type="button" value="click me"/> </div> </body> </html>
绑定后缓存热图:
通过此图我们可以看到这跟我们自己实现的缓存方式是非常类似的,只是多了一些额外的东西,比如名称空间(稍后会讲),事件委托。
另外提一个,因为一个事件类型可以有多个处理器函数,默认情况下,当你取消了冒泡行为时(event.stopPropagation),这多个处理器还 是会全部执行的,如果你想取消冒泡同时当前dom节点未执行的处理器函数也不执行了,则可以调用event. stopImmediatePropagation。
3.3 jQuery事件委托 (delegate)
首先,我们通过一个例子来看下什么是事件的委托。
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script type="text/javascript" src="jquery-1.7.1.js"></script> <script> $(function($){ var myTable = $("#mytable"); myTable.delegate("tr" , "dblclick", function(){alert("行双击");}); $("#add").click(function(){ $("<tr><td>123</td></tr>").appendTo(myTable); }); //不管你何时点击"添加"按钮,都会给表格新增一行 //不管是哪一行,只要在行上双击一行,都会弹出窗口显示 "行双击" //最神奇的是,我们根本没有显示给tr添加过"行双击"事件,而是通过委托的形式 }); </script> </head> <body> <table id="mytable"> </table> <input id="add" type="button" value="添加" /> </body> </html>
委托是种很方便的东西,说得白一点,就是孩子节点的事件处理器放在父节点的事件处理器列表中,让父节点统一来进行触发。如果没有这种机制的话,那么前面的例子就要单独给每个tr添加事件了,浪费了不少的空间,而且有时还要写多代码。
就上面这个例子我们看下委托后的缓存情况:
当我们双击了tr时,触发tr双击事件,然后冒泡到table,table根据delegateCount的值进行检查,因为 delegateCount=1,所以它会对table的事件处理器列表第一个函数(个数由delegateCount决定)进行检查,看它的 selector是否符合当前触发事件的源dom节点,结果发现刚刚匹配,说明此函数也是要执行的,再与后边剩余(总数-delegateCount)的 函数列表进行合并,成为最终的函数处理器列表,这便是事件委托。
最后提一句,在事件的处理上,jQuery1.7提供了两个堪称万能的api,分别是on和off,至于怎么用,就不多说了,文档一看就清楚了。
四. 名称空间
jQuery事件还有一个很新鲜的东西,那就是其独有的名称空间了。但是此名称空间与我们普通想的却是不太一样的,来看看jQuery的处理就知道怎么回事了。
首先介绍一下这个名称空间。我们在绑定事件时可以这样来绑定,$(“#btn”).bind(“click.www.jquery.com”, fn); 看到了吗,在事件类型后边可以加上”.www.jquery.com”这串东西,这整整一串就称为名称空间。(不要自以为www是一级,jquery是一 级,com是一级),在这里是没有多级这种概念的。在保存这个名称空间的时候,jQuery会这样做: 把www.jquery.com进行split,得到[“www”,”jquery”,”com”],然后进行sort,得到[“com” , “jquery” , “www”],然后再进行join得到com.jquery.www,最后保存在缓存当中。而当我们利用trigger想触发某个事件时,比如我们执 行$(“#btn”).trigger(“click”),这时候jQuery是这样处理的:“click”并没有名称空间,只有纯粹的类型,所以触发所 有类型为click的函数处理器(不管名称空间是什么),但有一个特例,也就是”!”号的使用,如果你刚刚写的是 $(“#btn”).trigger(“click!”),那么只会触发类型为click,并且名称空间为空的函数处理器。
另外一种就是我们触发有名称空间的事件了,比如$(“#btn”).trigger(“click.jquery.com”),这时候又怎么处理呢?
click.jquery.com 的名称空间为 jquery.com,split一下,变成[“jquery”,”com”],再sort一下,成[“com” , “jquery”],再join一下,成“com.jquery”,然后依次检查click类型的处理器,看看它的名称空间是否匹 配”com.jquery”,此例的匹配是这样的:/(^|\.)com\.(?:.*\.)?jquery(\.|$) /.test(“com.jquery.www”);左边的//正则是动态产生出来的,而test()中的” com.jquery.www”则是处理器中的名称空间,只要这个匹配成功了,那么该处理器便会得到执行。显然此例子是匹配成功的。关于这个正则就不多说 了,并不是很难看懂。
五. 后语
本文主要是对jQuery事件实现方式的一个解说,并展示了自己实现的一个简单版本的事件处理,希望可以帮助大家对JQuery事件的实现有更好的了解。
相关推荐
本压缩包文件"jquery1.7_20111204.rar"包含了jQuery 1.7版本的相关资料,特别是其中的"jquery1.7_20111204.chm"帮助文档,为开发者提供了详尽的API参考和使用示例。 一、jQuery核心概念 jQuery的核心理念是“写得...
jQuery1.7在前一版本的基础上进行了一系列优化和改进,包括性能提升和bug修复。这个离线手册包含了该版本的所有核心功能和API,对于初学者和经验丰富的开发者来说,都是一个宝贵的参考资料。 手册中的内容涵盖了...
jQuery 1.7是该库的一个重要版本,它包含了一系列的更新和改进,使得开发者在网页开发中更加得心应手。 ### jQuery 1.7 的主要特性 1. **选择器增强**:jQuery 1.7进一步增强了CSS选择器的支持,包括对更多高级CSS...
- **选择器(Selectors)**: jQuery 提供了一系列 CSS 选择器,如 `#id`、`.class` 和 `tagname`,使开发者能方便地选取网页元素。此外,还有更高级的选择器如 `:first`、`:last`、`:even` 和 `:contains(text)` 等...
在jQuery 1.7版本中,包含了一系列的改进和新特性,这些在中文API修正版中得到了充分的阐述。以下是一些关键知识点: 1. **选择器**:jQuery 1.7提供了强大的CSS选择器,如类选择器(`.class`)、ID选择器(`#id`)...
例如,通过jQuery 1.7的事件处理和数据操作功能,配合EasyUI的组件,可以轻松实现用户交互和动态数据加载。例如: - 使用.on() 绑定表格(Grid)的行点击事件,展示选中行的详细信息在Dialog中。 - 利用.data() ...
《jQuery 1.7 中文帮助文档》是一个针对jQuery 1.7版本的详细参考资料,旨在为中文用户提供了深入理解并高效使用该JavaScript库的途径。这个CHM(Compiled HTML Help)文件包含了丰富的API参考、教程和示例,是...
《jQuery1.7 中文手册》是一份详细记录jQuery 1.7版本特性和功能的文档,对于理解和应用这一版本的jQuery至关重要。jQuery是JavaScript的一个库,它极大地简化了JavaScript的DOM操作、事件处理、动画设计和Ajax交互...
在这一版本,jQuery 1.7,我们看到了一系列重要的改进和优化,使其成为Web开发中的得力助手。本文将详细介绍jQuery 1.7的核心特性、主要更新以及如何有效地使用它。 一、jQuery简介 jQuery是由John Resig创建的一...
1. **选择器**:jQuery 1.7提供了一系列强大的CSS选择器,如ID选择器(#id)、类选择器(.class)、属性选择器([attr=value])等,使得选取DOM元素变得简单。 2. **DOM操作**:jQuery提供了方便的DOM操作接口,如$...
`jquery1.7_20111204.chm`是jQuery 1.7 API的离线帮助文件,包含了所有1.7版本的函数、方法、选择器和事件的详细说明。这个CHM文件是Windows系统的帮助文件格式,用户可以通过它快速查找和学习jQuery的相关功能。 ...
**jQuery 1.7及其jQuery UI英文API CHM版**是两个重要的资源,对于深入理解和高效使用jQuery框架具有极大价值。这两个CHM(Compiled Help Manual)文件分别提供了jQuery 1.7版本和jQuery UI的详细文档,是开发者的...
对于初学者来说,`jquery1.7 中文手册.chm`是一个宝贵的资源,其中包含了详细的API文档和示例,可以帮助理解每个函数的用法和参数。通过深入学习和实践,开发者可以充分利用jQuery 1.7的特性,提高网页开发效率,...
《jQuery 1.7 中文手册》是一本详尽阐述jQuery 1.7版本核心功能和技术的案头参考书籍,适用于Web开发者,尤其是对JavaScript有基础了解并希望深入学习jQuery的人员。jQuery作为一款广泛使用的JavaScript库,极大地...
**jQuery 1.7 JS 知识点详解** jQuery 是一个高效、易用的JavaScript库,它极大地简化了HTML文档遍历、事件处理、动画设计和Ajax交互。jQuery 1.7是该库的一个重要版本,它包含了多个新特性、改进和bug修复,提升了...
本次我们将深入探讨jQuery 1.7版本,这个版本在1.x系列中具有重要的地位,引入了许多新特性和优化,进一步提升了性能和易用性。 首先,我们来看`jQuery1.6-api.chm`文件,这是一个帮助文档,详细介绍了jQuery 1.6...
描述中提到了"jquery1.7_20111204",这代表了jQuery库的一个特定版本——1.7.2,发布于2011年12月4日。jQuery是一个强大的JavaScript库,它简化了HTML文档遍历、事件处理、动画和Ajax交互,极大地提高了开发效率。在...
在jQuery 1.7中,`.on()`取代了`.bind()`, `.live()`, 和 `.delegate()`,成为统一的事件绑定方法,`.off()`则用于解除事件绑定。这两个方法的引入提高了代码的可读性和维护性。 8. **jQuery对象和DOM元素的转换**...
jQuery提供了一系列实用工具方法,如`$.each()`用于遍历对象和数组,`$.trim()`用于去除字符串两端的空白,`$.isFunction()`检查是否为函数,`$.inArray()`查找元素在数组中的位置,`$.extend()`用于合并对象。...
**jQuery 1.7中文帮助文档** jQuery是一个广泛使用的JavaScript库,它极大地简化了JavaScript的DOM操作、事件处理、动画制作以及Ajax交互。版本1.7是jQuery的一个重要里程碑,引入了许多新特性、优化和改进,同时...