从使用说起:

若干年前,有一天发现,通过js代码创建的html元素及ajax加载的html,无法被$([selector]).click(function(){...})绑定上事件,于是发现了jQuery的一个插件,livequery,然后就有了下面的这种写法:
  1. $("body").livequery("p",function(){
  2. $( this ).click(function(){
  3. $(this).after( "<p>Another paragraph!</p>" );
  4. });
  5. });
或者
  1. $("body>p").livequery("click",function(){
  2. $(this).after( "<p>Another paragraph!</p>" );
  3. });
这么久以来,有需要就这么写,也没有深究过livequery是如何监视dom变化的。最近的项目中大量使用了livequery,但也造成了一个问题,页面时间长了不刷新会变的非常卡,虽然在livequery绑定之前先expire可以缓解这个问题,但这毕竟是个心结,究竟怎么监视dom变化的?难道真如别人所说,定时器?
找到livequery的项目地址https://github.com/brandonaaron/livequery ,发现作者已经重构了livequery的核心方法,高版本的浏览器通过DOM Mutation对象实现,IE8及以下使用htcPath实现。
重点来了,作者在文档中说,事件绑定功能已经被移除,因为jQuery本身的delegation事件绑定已经很完美了。难道jQuery的的delegation可以实现异步dom的事件绑定吗,不对啊,之前试过,不好使啊,jQuery文档也没有对这些进行说明。但经过实验,$(selector).on(childSelector,event,function),这种写法,确实可以。但$(selector).on(event,function)不可以。
详情如下:
  1. //不可以
  2. window.onload = function(){
  3. $("body>p").click(function(){
  4. $( this ).after( "<p>Another paragraph!</p>" );
  5. });
  6. };
  7. //不可以
  8. window.onload = function() {
  9. $( "body>p" ).on( "click", function() {
  10. $( this ).after( "<p>Another paragraph!</p>" );
  11. });
  12. };
  13. //可以
  14. window.onload = function() {
  15. $( "body" ).on( "click","p", function() {
  16. $( this ).after( "<p>Another paragraph!</p>" );
  17. });
  18. };

虽然问题说到这里,livequery貌似没什么用了,因为用jQuery就可以实现想要的效果。但既然是奔着livequery的源码来的,那还是善事善终吧。

代码概览:

代码还是js惯用的风格: (function(xxx){...})(xxx)。首先定义了一个参数为factory的function,接着调用此function,并把livequery的核心函数作为参数。
function(factory)函数的目的是让livequery支持Amd规范,浏览器端针对模块的异步加载机制;及支持Browserify,CommonJS风格的模块加载机制。这些都不是重点,暂不讨论。重点是factory(jQuery)这一句。于是代码可以简写成:(function($){....})(jQuery)。
在livequery函数中,$.extend($.fn,{...})这一段,为jQuery扩展了两个插件:livequery,expire。
$.livequery = function(...){...}这一段定义了一个livequery类,并在接下来的$.livequery.prototype = {...}这一段中,为livequery类定义了added、removed等一系列函数。
$.extend($.livequery, {...})这一段为livequery扩展了一些静态属性及函数。其中比较重要的有queries,记录了所有的livequey创建的livequery对象;handle主要是一些用户处理livequery对象的方法,还有find、findOrCreate等。
该文件加载完毕后,最先执行的可以说是$(function(){...})这一段。这段代码的作用是,根据当前浏览器的环境,确定监视Dom变化的方式。 

如何监视Dom中元素的变化:

 
此处根据当前浏览器所支持的监视文档变换的对象,做了不同的记录,以便在根据不同的浏览器调用不同的方法。
window.MutationObserver:html5中提供的监视文档变化的方法,支持该方法的浏览器有:chrome,FireFox,safari, IE11+等。具体详细信息可以参考  http://javascript.ruanyifeng.com/dom/mutationobserver.html#toc4

在IE9、IE10中需要使用MutationEvent:http://msdn.microsoft.com/en-us/library/ie/ff974346(v=vs.85).aspx 
如果以上两个对象都不支持则进一步判断是否是低版本的IE:document.documentElement返回文档根元素即html节点,然后调用IE独有的document.documentElement.currentStyle获取元素的样式,并且判断IE独有的样式behaviour是否存在。如果满足这些条件,则表示当前浏览器是低版本的浏览器,使用iebehaviors进行标记。这种情况,livequery将会使用htcPath方式监视文档的变化。
这些代码中可以看到,livequery根据不同的情况,采取了不同的策略监控文档的变化。

通过代码调用livequery时,livequery究竟干了哪些事儿

  1. $("body").livequery("p",function(){
  2. $( this ).click(function(){
  3. $(this).after( "<p>Another paragraph!</p>" );
  4. });
  5. });

当通过以上方式调用livequery时,其实是调用了livequery的静态函数findorcreate。该函数new了一个livequery对象。该对象在构造函数中,给自己分配了一个唯一自增的id,并把自己加入到$.livequery.queries数组中,这个数组记录了所有的livequery对象。紧接着调用了该对象的run方法,在run方法中,通过一系列的调用,最终干了两件事儿:对当前元素进行标记,即存一份数据 data-livequery = id;以当前元素的身份调用指定的函数,即function(){ $(this).click(function(){....})}这段代码。

当有新的元素被创建并加载到dom中时,执行了哪些代码

假设浏览器支持window.MutationObserver对象,文档中有新元素被创建时,浏览器会回调 $.livequery.handle.mutationobserver 方法,该方法又调用了$.livequery.handle.added方法,added方法中会遍历$.livequery.queries数组,如果符合某个livequery对象的条件,则调用该对象的added方法,对象的added方法会干两件事:对当前元素进行标记,以当前元素的身份调用livequery对象所维护的方法。

livequery源码解读的更多相关文章

  1. SDWebImage源码解读之SDWebImageDownloaderOperation

    第七篇 前言 本篇文章主要讲解下载操作的相关知识,SDWebImageDownloaderOperation的主要任务是把一张图片从服务器下载到内存中.下载数据并不难,如何对下载这一系列的任务进行设计 ...

  2. SDWebImage源码解读 之 NSData+ImageContentType

    第一篇 前言 从今天开始,我将开启一段源码解读的旅途了.在这里先暂时不透露具体解读的源码到底是哪些?因为也可能随着解读的进行会更改计划.但能够肯定的是,这一系列之中肯定会有Swift版本的代码. 说说 ...

  3. SDWebImage源码解读 之 UIImage+GIF

    第二篇 前言 本篇是和GIF相关的一个UIImage的分类.主要提供了三个方法: + (UIImage *)sd_animatedGIFNamed:(NSString *)name ----- 根据名 ...

  4. SDWebImage源码解读 之 SDWebImageCompat

    第三篇 前言 本篇主要解读SDWebImage的配置文件.正如compat的定义,该配置文件主要是兼容Apple的其他设备.也许我们真实的开发平台只有一个,但考虑各个平台的兼容性,对于框架有着很重要的 ...

  5. SDWebImage源码解读_之SDWebImageDecoder

    第四篇 前言 首先,我们要弄明白一个问题? 为什么要对UIImage进行解码呢?难道不能直接使用吗? 其实不解码也是可以使用的,假如说我们通过imageNamed:来加载image,系统默认会在主线程 ...

  6. SDWebImage源码解读之SDWebImageCache(上)

    第五篇 前言 本篇主要讲解图片缓存类的知识,虽然只涉及了图片方面的缓存的设计,但思想同样适用于别的方面的设计.在架构上来说,缓存算是存储设计的一部分.我们把各种不同的存储内容按照功能进行切割后,图片缓 ...

  7. SDWebImage源码解读之SDWebImageCache(下)

    第六篇 前言 我们在SDWebImageCache(上)中了解了这个缓存类大概的功能是什么?那么接下来就要看看这些功能是如何实现的? 再次强调,不管是图片的缓存还是其他各种不同形式的缓存,在原理上都极 ...

  8. AFNetworking 3.0 源码解读 总结(干货)(下)

    承接上一篇AFNetworking 3.0 源码解读 总结(干货)(上) 21.网络服务类型NSURLRequestNetworkServiceType 示例代码: typedef NS_ENUM(N ...

  9. AFNetworking 3.0 源码解读 总结(干货)(上)

    养成记笔记的习惯,对于一个软件工程师来说,我觉得很重要.记得在知乎上看到过一个问题,说是人类最大的缺点是什么?我个人觉得记忆算是一个缺点.它就像时间一样,会自己消散. 前言 终于写完了 AFNetwo ...

随机推荐

  1. spring2.0包说明【转】

    Spring压缩包目录说明 关键字: sring jar 1. Spring压缩包目录说明 aspectj目录下是在Spring框架下使用aspectj的源代码和测试程序文件. Aspectj是jav ...

  2. arpg网页游戏之地图(三)

    地图分块加载类MapEngine,主要包含以下属性: g 地图层graphics,地图将画在上面 buffPixelRange 地图加载范围矩形 viewPort 屏幕视窗 currZoneArr 已 ...

  3. KMP算法简明扼要的理解

    KMP算法也算是相当经典,但是对于初学者来说确实有点绕,大学时候弄明白过后来几年不看又忘记了,然后再弄明白过了两年又忘记了,好在之前理解到了关键点,看了一遍马上又能理解上来.关于这个算法的详解网上文章 ...

  4. sqlserver 加内置dll的使用内存

  5. AX2012 DMF数据导入的问题

    由于AX2012的数据结构比较复杂,通过Excel直接导入表的方式很多数据已经难以导入,比如物料信息,2009只需要导入InventTable,InventTableModule和InventItem ...

  6. 7.29 H5学习笔记

    常用实体字符小于号  < 大于号  > 和号  & 引号  " 撇号  &apos; 分  ¢ 镑  £ 日元  ¥ 欧元  € 小节  § 版权  © 注册  ...

  7. linux C学习笔记04--内存映射

    内存映射代码,打开一个文件与映射到内存中,对内存和文件的修改都会反映到文件中来,反之亦然,先贴代码,以后再完善: /****************************************** ...

  8. position:absolute和float会隐式的改变display类型

    position:absolute和float会隐式的改变display类型,不论之前是什么类型的元素(display:none除外),只要设置了position:absolute或float,都会让 ...

  9. 如何用expdp、impdp按表空间导出、导入?

    参考:http://blog.csdn.net/zftang/article/details/6387325 A数据库: 表空间:ylcois 用户名:ylcois 密码:ylcois B数据库: 表 ...

  10. SegmentFault创始人高阳:辍学后带着500元北漂,4年建成国内最大开发者

    i黑马注:i黑马曾经和高阳聊过几次天,在他身上我看到了90后CEO特别明显的成功特质“敢为天下先”.在别人犹豫的时候敢第一个出手,在互联网时代往往会取得最关键的“先机优势”. 7月19日,“腾讯产品家 ...