您當(dāng)前位置:圖趣網(wǎng)(Tuquu) >> 網(wǎng)頁(yè)設(shè)計(jì)教程 >> 移動(dòng)前端 >> 瀏覽設(shè)計(jì)教程

網(wǎng)頁(yè)前端開(kāi)發(fā)jQuery事件編寫(xiě)進(jìn)階

 

jQuery事件編程進(jìn)階

事件委托,是一種優(yōu)化DOM元素事件綁定的技巧,利用事件冒泡的原理,通過(guò)綁定事件到父元素,檢查event觸發(fā)元素的target,最終執(zhí)行相應(yīng)的事件函數(shù)處理,它的幾個(gè)好處一般前端開(kāi)發(fā)程序員都知道。在jQuery中,一般是delegate()方法和.live()方法,但是,如何選擇事件委托的方法,或者在什么情況下用.live(),什么情況下用.delegate(),這個(gè)值得講一講:

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個(gè)事件委托的源代碼可知,live方法中,有個(gè)元素的執(zhí)行環(huán)境,這個(gè)執(zhí)行環(huán)境默認(rèn)是document,所以,如果把live事件委托寫(xiě)在$(document).ready(function() {})之外,也是沒(méi)有問(wèn)題的。live()在某種情況下會(huì)引起性能問(wèn)題,這主要包括2個(gè)方面:1.live()方法雖然避免了綁定事件處理到很多DOM元素,但是,它在一開(kāi)始選擇了文檔中的所有元素,如果一個(gè)文檔有很多的子節(jié)點(diǎn),比如文檔中的一個(gè)表有幾十列,幾百行表內(nèi)容,而事件要綁定到這個(gè)表的某一行某一列,那么,live()方法在一開(kāi)始選擇這個(gè)表的所有行,所有列的時(shí)候,就是一個(gè)非常大的性能消耗,會(huì)導(dǎo)致腳本反應(yīng)很遲鈍。2.因?yàn)閘ive()是綁定到document上面,所以會(huì)有大量的事件冒泡,事件冒泡要從嵌套最深的DOM元素往上一直冒到document上面,這樣長(zhǎng)路徑的事件冒泡也是一個(gè)很昂貴的性能消耗。而采用.delegate(),事件綁定到$()函數(shù)的選擇表達(dá)式元素上,因此頁(yè)面的事件注冊(cè)更加清晰,而事件冒泡更少。

 

由于初始化元素的選擇和過(guò)度的事件冒泡,開(kāi)發(fā)者們一般傾向于.delegate()方法,而擯棄.live()方法。但是,live()方法還是有其可用之處的,如果我們明智的使用它,過(guò)早的調(diào)用或者傳遞一個(gè)執(zhí)行環(huán)境給它(即設(shè)置它的context),live()就會(huì)趨利避害,發(fā)揮它的優(yōu)勢(shì)所在。其中一個(gè)改善live()性能的方法是把live()移出$(document).ready()之外,加入live()事件注冊(cè)的腳本是放在<head>結(jié)束標(biāo)簽之前,那么live()選擇元素的工作就會(huì)非常少,因?yàn)槟菚r(shí),整個(gè)DOM還沒(méi)有被加載注冊(cè),但document,這個(gè)live()的執(zhí)行環(huán)境,卻已經(jīng)可用了。

(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);

由于我們不必等待整個(gè)DOM加載完畢,我們就可以立即確定mouseenter 和mouseleave 的事件行為將應(yīng)用到<div>元素集上面,只要該元素集在頁(yè)面中一被渲染顯示就會(huì)起作用了。要理解這種事件注冊(cè)技術(shù)的好處,我們可以想像一下要綁定一個(gè)事件處理函數(shù)來(lái)阻止一個(gè)鏈接元素的單擊(click) 默認(rèn)行為。如果我們直到整個(gè)DOM已經(jīng)ready時(shí),才綁定click事件注冊(cè)函數(shù),那我們就要冒著在click事件注冊(cè)到那個(gè)鏈接元素之前,用戶(hù)點(diǎn)擊這個(gè)鏈接元素,從而導(dǎo)致瀏覽器離開(kāi)當(dāng)前頁(yè)面,而沒(méi)有采用ajax方式實(shí)現(xiàn)頁(yè)面的無(wú)刷新來(lái)更新內(nèi)容。Live()在早期注冊(cè),我們就有了事件早早綁定,卻避免掃描整個(gè)DOM結(jié)構(gòu)導(dǎo)致的性能消耗的好處。另一個(gè)使用.live()的技術(shù)是給它提供一個(gè)執(zhí)行環(huán)境(context),類(lèi)似于.delegate(),以此來(lái)減少事件冒泡。比如(‘div.photo’).live就改成$(‘div.photo’, $(‘#gallery’)[0]).live,這樣的話(huà),類(lèi)似于.delegate(),$(‘div.photo’, $(‘#gallery’)[0]).live必須放在$(document).ready()函數(shù)里面,但這樣也就失去了早期注冊(cè)的那些好處。

在jQuery 1.9版本中,已經(jīng)取消了live方法,但是這種在DOM加載早期,通過(guò)document事件委托綁定具體事件處理函數(shù),避免jQuery掃描整個(gè)DOM結(jié)構(gòu)導(dǎo)致的性能開(kāi)銷(xiāo)的編程思想確實(shí)有借鑒意義的。在jQuery 1.9中,上面用live的事件委托代碼可以改寫(xiě)成:

(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結(jié)束標(biāo)簽之前,這樣就不必等整個(gè)DOM加載完畢,通過(guò)document事件委托事先進(jìn)行針對(duì)div.photo元素的處理的事件綁定,避免jQuery掃描整個(gè)DOM結(jié)構(gòu)的性能開(kāi)銷(xiāo)。當(dāng)然,div.photo元素最好是body標(biāo)簽的直接子元素,這樣就可以減少事件冒泡的過(guò)程,如果div.photo在body下面嵌套比較深,則應(yīng)該權(quán)衡一下是否在$(document).ready()采用delegate方法代替。

jQuery的特殊事件

jQuery的自定義事件,功能很強(qiáng)大,但是特殊事件跟自定義事件的結(jié)合使用,可以在框架層面來(lái)解決一些代碼編寫(xiě)方面的問(wèn)題,類(lèi)似于java中的AOP切面編程。延遲事件執(zhí)行,我們來(lái)看下面一段代碼:

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

這里給窗體滾動(dòng)事件添加處理函數(shù),這個(gè)處理函數(shù)在窗體滾動(dòng)時(shí)每次延遲250毫秒執(zhí)行。如果不加延遲,瀏覽器哪怕滾動(dòng)一個(gè)像素,都會(huì)觸發(fā)checkScrollPosition()函數(shù)的調(diào)用,瀏覽器反復(fù)調(diào)用checkScrollPosition()函數(shù),可能會(huì)引起性能方面的問(wèn)題而導(dǎo)致瀏覽器進(jìn)入“假死狀態(tài)”,常見(jiàn)的窗體類(lèi)似事件有scroll, resize, 和 mousemove,給這些窗體事件添加處理函數(shù),希望都能添加延遲代碼,使事件延遲執(zhí)行,減少函數(shù)調(diào)用次數(shù),從而提升用戶(hù)體驗(yàn),給用戶(hù)比較平滑的瀏覽器效果體驗(yàn)。通過(guò)jQuery的特殊事件和自定義事件的結(jié)合,我們能夠優(yōu)化上面的事件延遲代碼,從而移除事件注冊(cè)中的setTimeout()函數(shù),類(lèi)似于java中的切面編程。這樣事件綁定中只要直接調(diào)用checkScrollPosition()方法,不再需要在外面再包裝setTimeout函數(shù)。請(qǐng)看以下示例:

(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');
});

這樣最大程度的簡(jiǎn)化了事件綁定的代碼,并且給了我們一個(gè)良好的可復(fù)用的事件延遲機(jī)制。因?yàn)槌舜绑w可以綁定throttledScroll事件,頁(yè)面中有滾動(dòng)條的其他div元素也可以綁定throttledScroll事件,而事件延遲寫(xiě)在$.event.special.throttledScroll的setup函數(shù)里面,這樣DOM只選要關(guān)心具體事件處理函數(shù)的實(shí)現(xiàn),不需要再手動(dòng)添加延遲代碼來(lái)改善性能。這樣編寫(xiě)代碼,結(jié)構(gòu)良好,代碼更清晰易懂,復(fù)用性也高。

[教程作者:admin]
免責(zé)聲明:本站文章系圖趣網(wǎng)整理發(fā)布,如需轉(zhuǎn)載,請(qǐng)注明出處,素材資料僅供個(gè)人學(xué)習(xí)與參考,請(qǐng)勿用于商業(yè)用途!
本文地址:http://irelandcustomcontracting.com/tutorial/wd1364.html
畫(huà)出你的風(fēng)格:HTML5創(chuàng)意畫(huà)板的設(shè)計(jì)教程
jQuery選擇器探討進(jìn)階
圖趣網(wǎng)微信
建議反饋
×