jQuery事件处理

  《jQuery基础教程》第三章——事件,读书笔记

  这一章主要是通过制作一个能够基于用户输入呈现出不同样式的页面来说明一些事件处理技术。

  涉及到的相关知识点有:

  • $(document).ready(): 通过$(document).ready()注册的事件处理程序,则会在DOM完全就绪并可以使用时调用
  • .bind(): 可以指定任何JavaScript事件,并为该事件添加一种行为。例:$('#switcher').bind( 'click', function() {...});
  • 当触发任何事件处理程序时,关键字this引用的都是携带相应行为的DOM元素;通过在事件处理程序中使用$(this),可以为相应的元素创建一个JQuery对象
  • .removeClass(): 移除类。当省略参数时,该方法会移除元素中所有类。例:removeClass('large')
  • 自定义事件处理程序:.ready().toggle().hover()
  • .toggle(): 接受两个参数,并且这两个参数都是函数。第一次单击调用第一个函数,第二次单击调用第二个函数,依此类推循环调参数函数。
              例:$('#switcher').toggle( function() {...}, function(){...});
  • .hover(): 接受两个参数,第一个函数会在鼠标指针进入被选择的元素时执行,第二个函数会在鼠标指标离开该元素时触发。
              例:$('.button').hover(function() {...}, function() {...});
  • 为提供跨浏览器的一致性,JQ始终会在模型的冒泡阶段注册事件处理程序。(就是JQ默认冒泡模式)
  • 事件捕获:在事件捕获过程中,事件首先会交给最外层的元素,接着再交给更具体的元素。
  • 事件冒泡:当事件发生时,会首先发送给最具体的元素,在这个元素获得响应机会之后,事件会冒泡到更一般的元素
  • 事件对象:事件对象是一种JavaScript结构,它会在元素获得处理事件的机会时被传递给被调用的事件处理程序。例:$('#switcher').click(function(event) {...});
  • 事件目标event.target属性保存着发生事件的目标元素。
  • .stopPropagation(): 事件对象提供的方法,可以完全阻止事件冒泡。例:event.stopPropagation()
  • .preventDefault(): 可以在触发默认操作之前终止事件。
  • .is(): 接收一个选择符表达式,然后用选择符来测试当前的jQuery对象。例:if( $( event.target ).is( '.button' ) )
  • .unbind(): 移除事件处理程序。例:$('#switcher').unbind('click')
  • 事件命名空间:即在绑定事件时引入附加信息,以便将来识别特定的处理程序。例:$('#switcher').unbind('click.collapse');
  • .trigger():可以完成模拟事件操作。例:$('#switcher').trigger('click');

    其中介绍了如何通过事件委托技术来进行事件处理,书中提到利用该技术取代隐式迭代,可以使得程序性能得到优化,并且使得程序运行所占用内存减少。

    虽然书上是这么写的,但还是需要仔细思考一下为什么使用事件委托就能够使得性能得到优化,看过的东西并不代表真的看懂了,即便无法深刻理解其中的原理,但是整理出自己的思路也是很有好处的,至少让读书的过程中有一些思考的成分,而不只是看过了就完事了——之前自己看书总是囫囵吞枣,一本书看下来其实收获甚少,现在要尝试逼着自己把看书的速度放慢,仔细思考,硬逼着在博客里写出点东西好像是个好法子。

    先给出相关的html和JS代码,两端JS实现的是一样的功能,就是按按钮,然后文本样式出现相应的变化,这里文本就不给出了:

按钮部分html:

<div id="switcher">
<h3>Style Switcher</h3>
<div class="button selected" id="switcher-default">
Default
</div>
<div class="button" id="switcher-narrow">
Narrow Column
</div>
<div class="button" id="switcher-large">
Large Print
</div>
</div>

实际页面:

Style Switcher

Default
Narrow Column
Large Print
 

/*隐式迭代*/

$('#switcher .button').bind('click', function(event) {       //为每个按钮的点击事件绑定函数——就是点击不同的按钮,文本应用不同的样式
  $('#switcher .button').removeClass('selected');        //先移除按钮上字体加粗('select')效果
  $(this).addClass('selected');                                   //为单击的按钮增加字体加粗效果,使用$(this)为相应元素创建一个jQuery对象,再对该元素进行操作
  $('body').removeClass();                                       //移除body元素的所有类
  if (this.id === 'switcher-large') {                            //当点击按钮id为switcher-large时,对body元素应用相应样式
  $('body').addClass('large');
  } else if (this.id === 'switcher-narrow') {                //同上
  $('body').addClass('narrow');
  }
  event.stopPropagation();                                       //阻止事件冒泡,因为按钮的父元素也绑定了单击事件函数,单击了按钮之后,单击事件会冒泡传递给父元素,使得父元素的单击事件也发生,为了阻止事件向上传递,因此需要使用这一方法——jQ始终会在模型的冒泡阶段注册事件处理程序(这句应该是jQ默认的事件传递机制就是事件冒泡的意思吧...)
});

/*事件委托*/
$('#switcher').click(function(event) {
  if ($(event.target).is('.button')) {
    $('body').removeClass();
    if (event.target.id === 'switcher-large') {
      $('body').addClass('large');
    } else if (event.target.id === 'switcher-narrow') {
      $('body').addClass('narrow');
    }
    $('#switcher .button').removeClass('selected');
    $(event.target).addClass('selected');
    }
});

    接下来看看事件委托跟上面的程序有什么区别(两个实现的功能是一样的)。

    1.下面这个程序为'#switcher'这个元素绑定了单击事件,而不是向按钮元素'#switcher .button'绑定单击事件。这里就是利用了事件冒泡传递,无论单击该元素的任何一个子元素,单击事件最终都会传递到该祖先元素中。

    2.使用event.target来确定目标元素——就是点击的具体元素。而通过条件if ($(event.target).is('.button'))来判断是否按钮并执行相应操作。上面的程序在进行条件判断的时候使用的是$(this)对象,但这里的$(this)对象是整个'#switcher'元素。因此,需要将程序中的$(this)对象更改为$(event.target)对象。

    那么做这些改变的目的在哪,是怎么实现的优化,以下是我的一些理解:

    使用隐式迭代的程序,选择了所有按钮,并为每个按钮绑定了click事件,这里相当于使用javascript进行了一个for循环,只是jQ把这个过程隐藏起来了。

    而使用事件委托的程序,为按钮的父元素绑定了一个单击事件(这就不需要循环遍历各个按钮元素了),而通过event.target来判断是否点击按钮元素,并执行相应操作。就是说,没有为每个按钮绑定事件,而是通过事件对象的属性来判断该进行何种操作。

    从性能上来说,事件委托没有进行循环操作,在存在较多需要绑定事件的元素的情况下(比如10000个按钮),在性能上是能够有很大提升的。

    从程序占用的内存来看,隐式迭代为每个按钮都绑定了一个单击事件,虽然对于浏览器运行程序的过程不是很清楚,但是为每个按钮绑定函数应该是需要为这些函数留出空间的,按钮越多,需要绑定的函数就越多,占用内存空间就越大。而使用事件委托,只为一个祖先元素绑定了一个事件函数,占用内存必然就小了许多。

  

posted @ 2012-06-09 18:40  糙哥  阅读(312)  评论(0编辑  收藏  举报