網(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è)鏈接元素之前,用戶點(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),類似于.delegate(),以此來(lái)減少事件冒泡。比如(‘div.photo’).live就改成$(‘div.photo’, $(‘#gallery’)[0]).live,這樣的話,類似于.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)銷的編程思想確實(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)銷。當(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)題,類似于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)的窗體類似事件有scroll, resize, 和 mousemove,給這些窗體事件添加處理函數(shù),希望都能添加延遲代碼,使事件延遲執(zhí)行,減少函數(shù)調(diào)用次數(shù),從而提升用戶體驗(yàn),給用戶比較平滑的瀏覽器效果體驗(yàn)。通過(guò)jQuery的特殊事件和自定義事件的結(jié)合,我們能夠優(yōu)化上面的事件延遲代碼,從而移除事件注冊(cè)中的setTimeout()函數(shù),類似于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ù)用性也高。
本文地址:http://www.likemindfilms.com/tutorial/wd1364.html
您可能還喜歡
- jquery Jcrop圖像裁切插件中文api文檔
- @media適配不同尺寸的手機(jī)
- 返回上一頁(yè)代碼的幾種寫(xiě)法
- Dreamweaver CC 2014新功能介紹
- 深入了解viewport和px
- 優(yōu)秀CSS代碼書(shū)寫(xiě)的10個(gè)規(guī)范
- 畫(huà)出你的風(fēng)格:HTML5創(chuàng)意畫(huà)板的設(shè)計(jì)教程
- Div中height:100%無(wú)效的解決辦法
- 網(wǎng)頁(yè)前端-網(wǎng)頁(yè)切圖命名規(guī)范
- 為網(wǎng)頁(yè)設(shè)計(jì)師而生的14個(gè)文本編輯器
- 專訪:石墨文檔產(chǎn)品總監(jiān)羅穎
- UI設(shè)計(jì)不得不知的移動(dòng)端UI尺寸適
- 光音移動(dòng)設(shè)計(jì)規(guī)范 — 表單類
- 體驗(yàn)設(shè)計(jì)中的排序問(wèn)題
- 網(wǎng)頁(yè)設(shè)計(jì)精粹 網(wǎng)頁(yè)中那些迷人的按
- aliued:響應(yīng)式設(shè)計(jì)的現(xiàn)狀與趨勢(shì)
- 10個(gè)智能對(duì)象處理的ps技巧
- 網(wǎng)頁(yè)UI - 原子設(shè)計(jì)理論(上)
- 如何通過(guò)設(shè)計(jì)提升banner點(diǎn)擊率?
- 晉小彥視覺(jué)設(shè)計(jì)系列文章(二):全屏