JavaScript的jQuery庫中ready方法的學(xué)習(xí)教程
學(xué)習(xí) jQuery 有許多途徑,我們今天從 jQuery 的 ready 函數(shù)開始。本例中的代碼都來自于 jQuery 腳本庫。
如果你使用過 jQuery , 就必然使用過 ready 函數(shù),它用來注冊當(dāng)頁面準(zhǔn)備好之后可以執(zhí)行的函數(shù)。
問題來啦,我們的頁面什么時候準(zhǔn)備好了呢?
onload 事件
最基本的處理方式就是頁面的 onload 事件,我們在處理這個事件的時候,可以有多種方式,即可以通過 HTML 方式,直接寫在 body 元素的開始標(biāo)記中,也可以使用事件注冊的方式來使用,這又可以分為 DOM0 方式和 DOM2 方式。再考慮到瀏覽器的兼容性,使用 DOM2 方式寫出來,如下所示。
if (document.addEventListener) { // A fallback to window.onload, that will always work window.addEventListener("load", jQuery.ready, false); // If IE event model is used } else { // A fallback to window.onload, that will always work window.attachEvent("onload", jQuery.ready); }
DOMContentLoaded 事件
不過 onload 事件要等到所有頁面元素加載完成才會觸發(fā), 包括頁面上的圖片等等。如果網(wǎng)頁上有大量的圖片,效果可想而知,用戶可能在沒有看到圖片的時候,就已經(jīng)開始操作頁面了,而這時我們的頁面還沒有初始化,事件還沒有注冊上,這豈不是太晚了!
除了大家熟知的 onload 事件之外, 與 DOM 中的 onload 事件相近的,我們還有 DOMContentLoaded 事件可以考慮, 基于標(biāo)準(zhǔn)的瀏覽器支持這個事件, 當(dāng)所有 DOM 解析完以后會觸發(fā)這個事件。
這樣,對于基于標(biāo)準(zhǔn)的瀏覽器來說,我們還可以注冊這個事件的處理。這樣,我們可能更早地捕獲到加載完成的事件。
if (document.addEventListener) { // Use the handy event callback document.addEventListener("DOMContentLoaded", DOMContentLoaded, false); // A fallback to window.onload, that will always work window.addEventListener("load", jQuery.ready, false); }
onreadystatechange 事件
不標(biāo)準(zhǔn)的瀏覽器怎么辦呢?
如果瀏覽器存在 document.onreadystatechange 事件,當(dāng)該事件觸發(fā)時,如果 document.readyState=complete 的時候,可視為 DOM 樹已經(jīng)載入。
不過,這個事件不太可靠,比如當(dāng)頁面中存在圖片的時候,可能反而在 onload 事件之后才能觸發(fā),換言之,它只能正確地執(zhí)行于頁面不包含二進(jìn)制資源或非常少或者被緩存時作為一個備選吧。
if (document.addEventListener) { // Use the handy event callback document.addEventListener("DOMContentLoaded", DOMContentLoaded, false); // A fallback to window.onload, that will always work window.addEventListener("load", jQuery.ready, false); // If IE event model is used } else { // Ensure firing before onload, maybe late but safe also for iframes document.attachEvent("onreadystatechange", DOMContentLoaded); // A fallback to window.onload, that will always work window.attachEvent("onload", jQuery.ready); }
DOMContentLoaded 函數(shù)在做什么呢?最終還是要調(diào)用 jQuery.ready 函數(shù)。
DOMContentLoaded = function() { if ( document.addEventListener ) { document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); jQuery.ready(); } else if ( document.readyState === "complete" ) { // we're here because readyState === "complete" in oldIE // which is good enough for us to call the dom ready! document.detachEvent( "onreadystatechange", DOMContentLoaded ); jQuery.ready(); } }doScroll 檢測法
MSDN 關(guān)于 JScript 的一個方法有段不起眼的話,當(dāng)頁面 DOM 未加載完成時,調(diào)用 doScroll 方法時,會產(chǎn)生異常。那么我們反過來用,如果不異常,那么就是頁面DOM加載完畢了!
Diego Perini 在 2007 年的時候,報告了一種檢測 IE 是否加載完成的方式,使用 doScroll 方法調(diào)用。詳細(xì)的說明見這里。
原理是對于 IE 在非 iframe 內(nèi)時,只有不斷地通過能否執(zhí)行 doScroll 判斷 DOM 是否加載完畢。在本例中每間隔 50 毫秒嘗試去執(zhí)行 doScroll,注意,由于頁面沒有加載完成的時候,調(diào)用 doScroll 會導(dǎo)致異常,所以使用了 try -catch 來捕獲異常。
(function doScrollCheck() { if (!jQuery.isReady) { try { // Use the trick by Diego Perini // http://javascript.nwbox.com/IEContentLoaded/ top.doScroll("left"); } catch (e) { return setTimeout(doScrollCheck, 50); } // and execute any waiting functions jQuery.ready(); } })();
document.readyState 狀態(tài)
如果我們注冊 ready 函數(shù)的時間點(diǎn)太晚了,頁面已經(jīng)加載完成之后,我們才注冊自己的 ready 函數(shù),那就用不著上面的層層檢查了,直接看看當(dāng)前頁面的 readyState 就可以了,如果已經(jīng)是 complete ,那就可以直接執(zhí)行我們準(zhǔn)備注冊的 ready 函數(shù)了。不過 ChrisS 報告了一個很特別的錯誤情況,我們需要延遲一下執(zhí)行。
setTimeout 經(jīng)常被用來做網(wǎng)頁上的定時器,允許為它指定一個毫秒數(shù)作為間隔執(zhí)行的時間。當(dāng)被啟動的程序需要在非常短的時間內(nèi)運(yùn)行,我們就會給她指定一個很小的時間數(shù),或者需要馬上執(zhí)行的話,我們甚至把這個毫秒數(shù)設(shè)置為0,但事實(shí)上,setTimeout有一個最小執(zhí)行時間,當(dāng)指定的時間小于該時間時,瀏覽器會用最小允許的時間作為setTimeout的時間間隔,也就是說即使我們把setTimeout的毫秒數(shù)設(shè)置為0,被調(diào)用的程序也沒有馬上啟動。
這個最小的時間間隔是多少呢?這和瀏覽器及操作系統(tǒng)有關(guān)。在John Resig的新書《Javascript忍者的秘密》一書中提到
Browsers all have a 10ms minimum delay on OSX and a(approximately) 15ms delay on Windows.(在蘋果機(jī)上的最小時間間隔是10毫秒,在Windows系統(tǒng)上的最小時間間隔大約是15毫秒)
,另外,MDC中關(guān)于setTimeout的介紹中也提到,F(xiàn)irefox中定義的最小時間間隔(DOM_MIN_TIMEOUT_VALUE)是10毫秒,HTML5定義的最小時間間隔是4毫秒。既然規(guī)范都是這樣寫的,那看來使用setTimeout是沒辦法再把這個最小時間間隔縮短了。
這樣,通過設(shè)置為 1, 我們可以讓程序在瀏覽器支持的最小時間間隔之后執(zhí)行了。
// Catch cases where $(document).ready() is called after the browser event has already occurred. // we once tried to use readyState "interactive" here, but it caused issues like the one // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 if (document.readyState === "complete") { // 延遲 1 毫秒之后,執(zhí)行 ready 函數(shù) setTimeout(jQuery.ready, 1); }
完整的代碼
在 jQuery 中完整的代碼如下所示。位于 jQuery 1.8.3 源代碼的 #842 行。
jQuery.ready.promise = function( obj ) { if ( !readyList ) { readyList = jQuery.Deferred(); // Catch cases where $(document).ready() is called after the browser event has already occurred. // we once tried to use readyState "interactive" here, but it caused issues like the one // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 if ( document.readyState === "complete" ) { // Handle it asynchronously to allow scripts the opportunity to delay ready setTimeout( jQuery.ready, 1 ); // Standards-based browsers support DOMContentLoaded } else if ( document.addEventListener ) { // Use the handy event callback document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); // A fallback to window.onload, that will always work window.addEventListener( "load", jQuery.ready, false ); // If IE event model is used } else { // Ensure firing before onload, maybe late but safe also for iframes document.attachEvent( "onreadystatechange", DOMContentLoaded ); // A fallback to window.onload, that will always work window.attachEvent( "onload", jQuery.ready ); // If IE and not a frame // continually check to see if the document is ready var top = false; try { top = window.frameElement == null && document.documentElement; } catch(e) {} if ( top && top.doScroll ) { (function doScrollCheck() { if ( !jQuery.isReady ) { try { // Use the trick by Diego Perini // http://javascript.nwbox.com/IEContentLoaded/ top.doScroll("left"); } catch(e) { return setTimeout( doScrollCheck, 50 ); } // and execute any waiting functions jQuery.ready(); } })(); } } } return readyList.promise( obj ); };
那么,又是誰來調(diào)用呢?當(dāng)然是需要的時候,在我們調(diào)用 ready 函數(shù)的時候,才需要注冊這些判斷頁面是否完全加載的處理,這段代碼在 1.8.3 中位于代碼的 #244 行,如下所示:
ready: function( fn ) { // Add the callback jQuery.ready.promise().done( fn ); return this; }
在頁面上引用 jQuery 腳本庫之后,執(zhí)行了 jQuery 的初始化函數(shù),初始化函數(shù)中創(chuàng)建了 ready 函數(shù)。我們在通過 ready 函數(shù)注冊事件處理之前,jQuery 完成了頁面檢測代碼的注冊。這樣。當(dāng)頁面完全加載之后,我們注冊的函數(shù)就被調(diào)用了。
jQuery Ready 方法的簡短寫法
寫 jQuery 代碼的時候,一般要寫一個 Ready 方法,以確保 DOM 已加載完畢,然后再執(zhí)行相應(yīng)的 jQuery 代碼。Ready 方法一般寫法如下:
$(document).ready(function() { // 從這里開始 });
但是在看其他人寫的 jQuery 代碼的時候,經(jīng)常又會看到如下寫法:
$(function() { // 從這里開始 });
第二種寫法雖然簡短了許多,但是在功能上和第一種寫法是等價的,如果你不相信,可以看一下 jQuery 的源代碼中有如下代碼片段:
// HANDLE: $(function) // Shortcut for document ready if ( jQuery.isFunction( selector ) ) { return rootjQuery.ready( selector ); }
如果傳入選擇器中的參數(shù)是一個函數(shù),那么會自動返回一個 rootjQuery.ready( selector ),而 rootjQuery 又是 jQuery(document) 的一個引用,所以這里就相當(dāng)于調(diào)用 jQuery(document).ready() 方法,而之前的那個匿名方法亦被傳入其中以備執(zhí)行。
這種簡短寫法雖說減少了了一點(diǎn)代碼量,但是可讀性稍差,所以我個人還是傾向于前面的第一種寫法,特別是在團(tuán)隊(duì)開發(fā)中,僅僅是為了語意明確。
- 用javascript實(shí)現(xiàn)jquery的document.ready功能的實(shí)現(xiàn)代碼
- JQuery的ready函數(shù)與JS的onload的區(qū)別詳解
- 模擬jQuery中的ready方法及實(shí)現(xiàn)按需加載css,js實(shí)例代碼
- JQuery的read函數(shù)與js的onload不同方式實(shí)現(xiàn)
- javascript 模擬JQuery的Ready方法實(shí)現(xiàn)并出現(xiàn)的問題
- jQuery中的read和JavaScript中的onload函數(shù)的區(qū)別
- 全面解析jQuery $(document).ready()和JavaScript onload事件
- jquery $(document).ready() 與window.onload的區(qū)別
- jQuery之$(document).ready()使用介紹
- jQuery的Read()方法代替原生JS詳解
相關(guān)文章
jquery實(shí)現(xiàn)的鼠標(biāo)下拉滾動置頂效果
鼠標(biāo)下拉滾動置頂效果想必大家在瀏覽網(wǎng)頁時都有遇到過,下面有個不錯的小例子,需要的朋友可以參考下2014-07-07jQuery插件FusionCharts繪制的3D餅狀圖效果實(shí)例【附demo源碼下載】
這篇文章主要介紹了jQuery插件FusionCharts繪制的3D餅狀圖效果,結(jié)合完整實(shí)例形式分析了基于FusionCharts圖形插件繪制餅狀圖的操作技巧,并附帶demo源碼供讀者下載參考,需要的朋友可以參考下2017-03-03jquery原創(chuàng)彈出層折疊效果點(diǎn)擊折疊彈出一個層
今天整理最近項(xiàng)目里用到的一個小效果,點(diǎn)擊折疊彈出一個層給用戶填寫信息,感興趣的朋友可以學(xué)習(xí)下2014-03-03jquery.validate使用攻略 第五步 正則驗(yàn)證
一些常用的驗(yàn)證腳本2010-07-07