IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

jQuery事件编写进阶

阿里巴巴(中国站)用户体验设计部博客 2013-03-05 13:16:08 累计浏览 4,259 次
本机暂存

jQuery事件编程进阶

事件委托,是一种优化DOM元素事件绑定的技巧,利用事件冒泡的原理,通过绑定事件到父元素,检查event触发元素的target,最终执行相应的事件函数处理,它的几个好处一般前端开发程序员都知道。在jQuery中,一般是delegate()方法和.live()方法,但是,如何选择事件委托的方法,或者在什么情况下用.live(),什么情况下用.delegate(),这个值得讲一讲:

live: function( types, data, fn ) {
      jQuery( this.context ).on( types, this.selector, data, fn );
      return this;
    }
delegate: function( selector, types, data, fn ) {
      return this.on( types, selector, data, fn );
}

查看这2个事件委托的源代码可知,live方法中,有个元素的执行环境,这个执行环境默认是document,所以,如果把live事件委托写在$(document).ready(function() {})之外,也是没有问题的。live()在某种情况下会引起性能问题,这主要包括2个方面:1.live()方法虽然避免了绑定事件处理到很多DOM元素,但是,它在一开始选择了文档中的所有元素,如果一个文档有很多的子节点,比如文档中的一个表有几十列,几百行表内容,而事件要绑定到这个表的某一行某一列,那么,live()方法在一开始选择这个表的所有行,所有列的时候,就是一个非常大的性能消耗,会导致脚本反应很迟钝。2.因为live()是绑定到document上面,所以会有大量的事件冒泡,事件冒泡要从嵌套最深的DOM元素往上一直冒到document上面,这样长路径的事件冒泡也是一个很昂贵的性能消耗。而采用.delegate(),事件绑定到$()函数的选择表达式元素上,因此页面的事件注册更加清晰,而事件冒泡更少。

由于初始化元素的选择和过度的事件冒泡,开发者们一般倾向于.delegate()方法,而摈弃.live()方法。但是,live()方法还是有其可用之处的,如果我们明智的使用它,过早的调用或者传递一个执行环境给它(即设置它的context),live()就会趋利避害,发挥它的优势所在。其中一个改善live()性能的方法是把live()移出$(document).ready()之外,加入live()事件注册的脚本是放在<head>结束标签之前,那么live()选择元素的工作就会非常少,因为那时,整个DOM还没有被加载注册,但document,这个live()的执行环境,却已经可用了。

(function($) {
   $('div.photo').live('mouseenter mouseleave',
    function(event) {
      var $details = $(this).find('.details');
      if (event.type == 'mouseenter') {
        $details.fadeTo('fast', 0.7);
       } else {
     $details.fadeOut('fast');
    }
});
})(jQuery);

由于我们不必等待整个DOM加载完毕,我们就可以立即确定mouseenter 和mouseleave 的事件行为将应用到<div>元素集上面,只要该元素集在页面中一被渲染显示就会起作用了。要理解这种事件注册技术的好处,我们可以想像一下要绑定一个事件处理函数来阻止一个链接元素的单击(click) 默认行为。如果我们直到整个DOM已经ready时,才绑定click事件注册函数,那我们就要冒着在click事件注册到那个链接元素之前,用户点击这个链接元素,从而导致浏览器离开当前页面,而没有采用ajax方式实现页面的无刷新来更新内容。Live()在早期注册,我们就有了事件早早绑定,却避免扫描整个DOM结构导致的性能消耗的好处。另一个使用.live()的技术是给它提供一个执行环境(context),类似于.delegate(),以此来减少事件冒泡。比如(‘div.photo’).live就改成$(‘div.photo’, $(‘#gallery’)[0]).live,这样的话,类似于.delegate(),$(‘div.photo’, $(‘#gallery’)[0]).live必须放在$(document).ready()函数里面,但这样也就失去了早期注册的那些好处。

   在jQuery 1.9版本中,已经取消了live方法,但是这种在DOM加载早期,通过document事件委托绑定具体事件处理函数,避免jQuery扫描整个DOM结构导致的性能开销的编程思想确实有借鉴意义的。在jQuery 1.9中,上面用live的事件委托代码可以改写成:

(function($) {
   $(document).on('mouseenter mouseleave','div.photo'
    function(event) {
      var $details = $(this).find('.details');
      if (event.type == 'mouseenter') {
        $details.fadeTo('fast', 0.7);
       } else {
     $details.fadeOut('fast');
    }
});
})(jQuery);

   如果把这段代码放在head结束标签之前,这样就不必等整个DOM加载完毕,通过document事件委托事先进行针对div.photo元素的处理的事件绑定,避免jQuery扫描整个DOM结构的性能开销。当然,div.photo元素最好是body标签的直接子元素,这样就可以减少事件冒泡的过程,如果div.photo在body下面嵌套比较深,则应该权衡一下是否在$(document).ready()采用delegate方法代替。

jQuery的特殊事件

jQuery的自定义事件,功能很强大,但是特殊事件跟自定义事件的结合使用,可以在框架层面来解决一些代码编写方面的问题,类似于java中的AOP切面编程。延迟事件执行,我们来看下面一段代码:

$(document).ready(function() {
  var timer = 0;
  $window.scroll(function() {
   if (!timer) {
   timer = setTimeout(function() {
   checkScrollPosition();
   timer = 0;
   }, 250);
  }
  }).scroll();
});

这里给窗体滚动事件添加处理函数,这个处理函数在窗体滚动时每次延迟250毫秒执行。如果不加延迟,浏览器哪怕滚动一个像素,都会触发checkScrollPosition()函数的调用,浏览器反复调用checkScrollPosition()函数,可能会引起性能方面的问题而导致浏览器进入“假死状态”,常见的窗体类似事件有scroll, resize, 和 mousemove,给这些窗体事件添加处理函数,希望都能添加延迟代码,使事件延迟执行,减少函数调用次数,从而提升用户体验,给用户比较平滑的浏览器效果体验。通过jQuery的特殊事件和自定义事件的结合,我们能够优化上面的事件延迟代码,从而移除事件注册中的setTimeout()函数,类似于java中的切面编程。这样事件绑定中只要直接调用checkScrollPosition()方法,不再需要在外面再包装setTimeout函数。请看以下示例:

(function($) {
$.event.special.throttledScroll = {
  setup: function(data) {
   var timer = 0;
   $(this).bind('scroll.throttledScroll', function(event) {
    if (!timer) {
    timer = setTimeout(function() {
     $(this).triggerHandler('throttledScroll');
     timer = 0;
     }, 250);
    }
   });
  },
  teardown: function() {
   $(this).unbind('scroll.throttledScroll');
  }
 };
})(jQuery);
$(document).ready(function() {
   $window.bind('throttledScroll', checkScrollPosition).trigger('throttledScroll');
});

这样最大程度的简化了事件绑定的代码,并且给了我们一个良好的可复用的事件延迟机制。因为除了窗体可以绑定throttledScroll事件,页面中有滚动条的其他div元素也可以绑定throttledScroll事件,而事件延迟写在$.event.special.throttledScroll的setup函数里面,这样DOM只选要关心具体事件处理函数的实现,不需要再手动添加延迟代码来改善性能。这样编写代码,结构良好,代码更清晰易懂,复用性也高。

同分类推荐文章

  1. translateZ() (2026-06-25 21:18:56)
  2. translateY() (2026-06-25 21:17:56)
  3. translateX() (2026-06-25 21:16:01)

查看更多 前端 文章 →

建议继续学习

  1. JQuery实现Excel表格呈现 (累计阅读 48,350)
  2. 分享一个JQUERY颜色选择插件 (累计阅读 14,223)
  3. jQuery插件---轻量级的弹出窗口wBox. (累计阅读 10,773)
  4. 10个强大的Ajax jQuery文件上传程序 (累计阅读 8,854)
  5. jQuery性能优化指南 (累计阅读 8,819)
  6. jQuery的data()方法 (累计阅读 8,651)
  7. jQuery Color Animations颜色动画插件 (累计阅读 8,506)
  8. 精于图片处理的10款jQuery插件 (累计阅读 7,366)
  9. 配合jquery实现异步加载页面元素 (累计阅读 6,394)
  10. jQuery中getJSON跨域原理详解 (累计阅读 6,352)