[英]jQuery Mobile: document ready vs. page events
我正在使用jQuery Mobile,並且無法理解經典文檔就緒和jQuery Mobile頁面事件之間的區別。
真正的區別是什么?
為什么要
<!-- language: lang-js --> $(document).ready() { });
勝過
$(document).on('pageinit') { });
從一頁切換到另一頁時,頁面事件的順序是什么?
如何將數據從一頁發送到另一頁,並且可以訪問前一頁的數據?
我的原始文章旨在用於頁面處理的舊方法,基本上是jQuery Mobile 1.4之前的所有內容。 現在不贊成使用舊的處理方式,它會一直保持有效狀態,直到(包括)jQuery Mobile 1.5,因此您仍然可以使用下面提到的所有功能,至少直到明年和jQuery Mobile 1.6為止。
包括pageinit在內的舊事件已不存在,它們已替換為pagecontainer小部件。 Pageinit被完全擦除,您可以使用pagecreate來代替,該事件保持不變,並且不會被更改。
如果您對頁面事件處理的新方法感興趣,請在此處查看 ,在任何其他情況下,請繼續閱讀本文。 即使您正在使用jQuery Mobile 1.4或更高版本,也應該閱讀此答案,它不僅僅包含頁面事件,因此您可能會發現很多有用的信息。
本文也可以在我的博客HERE中找到 。
$(document).on('pageinit')
與$(document).ready()
在jQuery中學習的第一件事是調用$(document).ready()
函數中的代碼,以便一旦加載DOM,一切都將執行。 但是,在jQuery Mobile中 ,Ajax用於在導航時將每個頁面的內容加載到DOM中。 因此, $(document).ready()
將在加載第一頁之前觸發,並且用於頁面操作的每個代碼都將在刷新頁面后執行。 這可能是一個非常微妙的錯誤。 在某些系統上,它似乎工作正常,但在其他系統上,則可能導致不穩定,難以重復的怪異現象發生。
經典jQuery語法:
$(document).ready(function() {
});
為了解決此問題(並相信我這是一個問題), jQuery Mobile開發人員創建了頁面事件。 簡而言之,頁面事件是在頁面執行的特定點觸發的事件。 這些頁面事件之一是pageinit事件,我們可以像這樣使用它:
$(document).on('pageinit', function() {
});
我們甚至可以走得更遠,使用頁面ID代替文檔選擇器。 假設我們有一個帶有id 索引的 jQuery Mobile頁面:
<div data-role="page" id="index">
<div data-theme="a" data-role="header">
<h3>
First Page
</h3>
<a href="#second" class="ui-btn-right">Next</a>
</div>
<div data-role="content">
<a href="#" data-role="button" id="test-button">Test button</a>
</div>
<div data-theme="a" data-role="footer" data-position="fixed">
</div>
</div>
要執行僅對索引頁可用的代碼,我們可以使用以下語法:
$('#index').on('pageinit', function() {
});
Pageinit事件將在每次將要第一次加載並顯示頁面時執行。 除非手動刷新頁面或關閉Ajax頁面加載,否則不會再次觸發。 如果您希望每次訪問頁面都執行代碼,最好使用pagebeforeshow事件。
這是一個工作示例: http : //jsfiddle.net/Gajotres/Q3Usv/來演示此問題。
關於這個問題的更多筆記。 無論您使用的是1個html多個頁面還是多個HTML文件范例,建議您將所有自定義JavaScript頁面處理都分成一個單獨的JavaScript文件。 這將使您的代碼變得更好,但是您將獲得更好的代碼概述,尤其是在創建jQuery Mobile應用程序時。
還有另一個特殊的jQuery Mobile事件,稱為mobileinit 。 jQuery Mobile啟動時,它將觸發文檔對象上的mobileinit事件。 要覆蓋默認設置,請將它們綁定到mobileinit 。 使用mobileinit的一個很好的例子是關閉Ajax頁面加載,或更改默認的Ajax加載器行為。
$(document).on("mobileinit", function(){
//apply overrides here
});
首先,所有事件都可以在這里找到: http : //api.jquerymobile.com/category/events/
假設我們有一個頁面A和一個頁面B,這是一個卸載/加載順序:
頁面B-事件pagebeforecreate
頁面B-事件頁面創建
頁面B-事件pageinit
A頁-事件pagebehidehide
頁面A-事件頁面刪除
A頁-事件pagehide
頁面B-事件頁面
頁面B-活動頁面顯示
為了更好地了解頁面事件,請閱讀以下內容:
pagebeforeload
, pageload
和pageloadfailed
當外部加載頁面時被解雇 pagebeforechange
, pagechange
和pagechangefailed
是頁面更改事件。 當用戶在應用程序中的頁面之間導航時,將觸發這些事件。 pagebeforeshow
, pagebeforehide
, pageshow
和pagehide
是頁面轉換事件。 這些事件在轉換之前,期間和之后都會觸發,並被命名。 pagebeforecreate
, pagecreate
和pageinit
用於頁面初始化。 pageremove
並進行處理 頁面加載jsFiddle示例: http : //jsfiddle.net/Gajotres/QGnft/
如果未啟用AJAX,則某些事件可能不會觸發。
如果出於某種原因需要在某種情況下防止頁面轉換,可以使用以下代碼完成:
$(document).on('pagebeforechange', function(e, data){
var to = data.toPage,
from = data.options.fromPage;
if (typeof to === 'string') {
var u = $.mobile.path.parseUrl(to);
to = u.hash || '#' + u.pathname.substring(1);
if (from) from = '#' + from.attr('id');
if (from === '#index' && to === '#second') {
alert('Can not transition from #index to #second!');
e.preventDefault();
e.stopPropagation();
// remove active status on a button, if transition was triggered with a button
$.mobile.activePage.find('.ui-btn-active').removeClass('ui-btn-active ui-focus ui-btn');;
}
}
});
該示例在任何情況下都可以使用,因為它將在每次頁面轉換的開始時觸發,最重要的是它將防止頁面轉換發生在頁面轉換之前。
這是一個工作示例:
jQuery Mobile
工作方式不同於經典Web應用程序。 根據每次訪問某個頁面時如何綁定事件的方式,綁定事件將一遍又一遍地進行。 這不是錯誤,只是jQuery Mobile
處理其頁面的方式。 例如,看下面的代碼片段:
$(document).on('pagebeforeshow','#index' ,function(e,data){
$(document).on('click', '#test-button',function(e) {
alert('Button click');
});
});
可用的jsFiddle示例: http : //jsfiddle.net/Gajotres/CCfL4/
每次您訪問頁面#index click事件都將綁定到#test-button按鈕 。 從第1頁移至第2頁並多次返回進行測試。 有幾種方法可以防止此問題:
最好的解決方案是使用pageinit
綁定事件。 如果您查看官方文檔,就會發現pageinit
僅會觸發一次,就像准備好文檔一樣,因此不可能再次綁定事件。 這是最好的解決方案,因為您沒有像使用off方法刪除事件時那樣的處理開銷。
可用的jsFiddle示例: http : //jsfiddle.net/Gajotres/AAFH8/
該工作解決方案是在先前有問題的示例的基礎上提出的。
在綁定事件之前將其刪除:
$(document).on('pagebeforeshow', '#index', function(){
$(document).off('click', '#test-button').on('click', '#test-button',function(e) {
alert('Button click');
});
});
可行的jsFiddle示例: http : //jsfiddle.net/Gajotres/K8YmG/
使用jQuery篩選器選擇器,如下所示:
$('#carousel div:Event(!click)').each(function(){
//If click is not bind to #carousel div do something
});
由於事件過濾器不是官方jQuery框架的一部分,因此可以在以下位置找到: http : //www.codenothing.com/archives/2009/event-filter/
簡而言之,如果您最關心速度,那么解決方案2比解決方案1更好。
一個新的,可能是最簡單的一個。
$(document).on('pagebeforeshow', '#index', function(){
$(document).on('click', '#test-button',function(e) {
if(e.handled !== true) // This will prevent event triggering more than once
{
alert('Clicked');
e.handled = true;
}
});
});
可用的jsFiddle示例: http : //jsfiddle.net/Gajotres/Yerv9/
對於此解決方案,請向sholsinger發送Tnx : http : //sholsinger.com/archive/2011/08/prevent-jquery-live-handlers-from-firing-multiple-times/
pageChange事件怪癖-觸發兩次
有時pagechange事件可以觸發兩次,並且與前面提到的問題無關。
pagebeforechange事件發生兩次的原因是由於toPage不是jQuery增強的DOM對象時changePage中的遞歸調用。 這種遞歸很危險,因為允許開發人員在事件內更改toPage。 如果開發人員在pagebeforechange事件處理程序中始終將toPage設置為字符串,則無論它是否是對象,都將導致無限遞歸循環。 pageload事件將新頁面作為數據對象的page屬性傳遞(應將其添加到文檔中,當前未列出)。 因此,pageload事件可用於訪問已加載的頁面。
簡而言之,這是因為您正在通過pageChange發送其他參數。
例:
<a data-role="button" data-icon="arrow-r" data-iconpos="right" href="#care-plan-view?id=9e273f31-2672-47fd-9baa-6c35f093a800&name=Sat"><h3>Sat</h3></a>
要解決此問題,請使用“頁面事件轉換順序”中列出的任何頁面事件。
如前所述,當您從一個jQuery Mobile頁面更改為另一頁面時,通常是通過單擊DOM中已經存在的另一個jQuery Mobile頁面的鏈接,或者通過手動調用$ .mobile.changePage來進行,會發生多個事件和后續操作。 在較高級別上,將發生以下操作:
這是一個平均頁面過渡基准:
頁面加載和處理: 3毫秒
頁面增強: 45毫秒
轉換時間: 604毫秒
總時間: 670毫秒
*這些值以毫秒為單位。
因此,您可以看到過渡事件幾乎消耗了90%的執行時間。
在頁面轉換期間,可以將參數從一個頁面發送到另一頁面。 它可以通過幾種方法來完成。
參考: https : //stackoverflow.com/a/13932240/1848600
解決方案1:
您可以使用changePage傳遞值:
$.mobile.changePage('page2.html', { dataUrl : "page2.html?paremeter=123", data : { 'paremeter' : '123' }, reloadPage : true, changeHash : true });
並像這樣閱讀它們:
$(document).on('pagebeforeshow', "#index", function (event, data) {
var parameters = $(this).data("url").split("?")[1];;
parameter = parameters.replace("parameter=","");
alert(parameter);
});
index.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="widdiv=device-widdiv, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> <meta name="apple-mobile-web-app-capable" content="yes" /> <meta name="apple-mobile-web-app-status-bar-style" content="black" /> <title> </title> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css" /> <script src="http://www.dragan-gaic.info/js/jquery-1.8.2.min.js"> </script> <script src="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js"></script> <script> $(document).on('pagebeforeshow', "#index",function () { $(document).on('click', "#changePage",function () { $.mobile.changePage('second.html', { dataUrl : "second.html?paremeter=123", data : { 'paremeter' : '123' }, reloadPage : false, changeHash : true }); }); }); $(document).on('pagebeforeshow', "#second",function () { var parameters = $(this).data("url").split("?")[1];; parameter = parameters.replace("parameter=",""); alert(parameter); }); </script> </head> <body> <!-- Home --> <div data-role="page" id="index"> <div data-role="header"> <h3> First Page </h3> </div> <div data-role="content"> <a data-role="button" id="changePage">Test</a> </div> <!--content--> </div><!--page--> </body> </html>
second.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="widdiv=device-widdiv, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> <meta name="apple-mobile-web-app-capable" content="yes" /> <meta name="apple-mobile-web-app-status-bar-style" content="black" /> <title> </title> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css" /> <script src="http://www.dragan-gaic.info/js/jquery-1.8.2.min.js"> </script> <script src="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js"></script> </head> <body> <!-- Home --> <div data-role="page" id="second"> <div data-role="header"> <h3> Second Page </h3> </div> <div data-role="content"> </div> <!--content--> </div><!--page--> </body> </html>
解決方案2:
或者,您可以創建一個持久性JavaScript對象以用於存儲。 只要將Ajax用於頁面加載(並且不會以任何方式重新加載頁面),該對象就會保持活動狀態。
var storeObject = {
firstname : '',
lastname : ''
}
示例: http : //jsfiddle.net/Gajotres/9KKbx/
解決方案3:
您還可以像這樣從上一頁訪問數據:
$(document).on('pagebeforeshow', '#index',function (e, data) {
alert(data.prevPage.attr('id'));
});
prevPage對象保存完整的上一頁。
解決方案4:
作為最后的解決方案,我們有一個很棒的localStorage HTML實現。 它僅適用於HTML5瀏覽器(包括Android和iOS瀏覽器),但所有存儲的數據都可以通過頁面刷新保持不變。
if(typeof(Storage)!=="undefined") {
localStorage.firstname="Dragan";
localStorage.lastname="Gaic";
}
示例: http : //jsfiddle.net/Gajotres/J9NTr/
可能是最佳解決方案,但在某些版本的iOS 5.X中將失敗。 這是一個眾所周知的錯誤。
.live()
/ .bind()
/ .delegate()
我忘了提及(和tnx andleer提醒我),不建議使用on / off進行事件綁定/解除綁定,不贊成使用live / die和bind / unbind。
jQuery的.live()方法在1.3版引入API時被視為天賜之物。 在典型的jQuery應用程序中,可能會有許多DOM操作,並且隨着元素的來去去去鈎掛和脫鈎會變得非常繁瑣。 .live()
方法可以根據應用程序的選擇器在應用程序的生命期內掛鈎事件。 很好嗎? 錯誤的.live()
方法非常慢。 .live()
方法實際上將其事件掛接到文檔對象,這意味着該事件必須從生成該事件的元素起泡直到到達文檔。 這可能非常耗時。
現在已棄用。 jQuery團隊的人們不再推薦使用它,我也不推薦使用。即使掛接和取消掛接事件可能很繁瑣,但是如果沒有.live()
方法,您的代碼將比使用它快得多。
代替.live()
您應該使用.on()
。 .on()
比.live()快大約2-3倍。 看一下該事件綁定基准: http : //jsperf.com/jquery-live-vs-delegate-vs-on/34 ,從那里可以清楚地看到所有內容。
jQuery Mobile頁面事件基准測試有一個出色的腳本。 可以在這里找到: https : //github.com/jquery/jquery-mobile/blob/master/tools/page-change-time.js 。 但是在您執行任何操作之前,我建議您刪除其alert
通知系統(每個“更改頁”將通過停止應用程序向您顯示此數據),並將其更改為console.log
函數。
基本上,此腳本將記錄您的所有頁面事件,如果您仔細閱讀本文(頁面事件描述),您將知道jQm在頁面增強,頁面轉換...上花費了多少時間。
始終如此,我的意思是始終閱讀jQuery Mobile官方文檔。 它通常會為您提供所需的信息,並且與某些其他文檔不同,該文檔非常好,帶有足夠的解釋和代碼示例。
你們中的有些人可能會發現這很有用。 只需將其復制粘貼到您的頁面上,您將獲得在Chrome控制台中觸發事件的順序( Ctrl + Shift + I )。
$(document).on('pagebeforecreate',function(){console.log('pagebeforecreate');});
$(document).on('pagecreate',function(){console.log('pagecreate');});
$(document).on('pageinit',function(){console.log('pageinit');});
$(document).on('pagebeforehide',function(){console.log('pagebeforehide');});
$(document).on('pagebeforeshow',function(){console.log('pagebeforeshow');});
$(document).on('pageremove',function(){console.log('pageremove');});
$(document).on('pageshow',function(){console.log('pageshow');});
$(document).on('pagehide',function(){console.log('pagehide');});
$(window).load(function () {console.log("window loaded");});
$(window).unload(function () {console.log("window unloaded");});
$(function () {console.log('document ready');});
您不會在控制台中看到卸載,因為在卸載頁面時(當您離開頁面時)會被觸發。 像這樣使用它:
$(window).unload(function () { debugger; console.log("window unloaded");});
您會明白我的意思。
這是正確的方法:
要執行僅對索引頁可用的代碼,我們可以使用以下語法:
$(document).on('pageinit', "#index", function() {
...
});
jQuery-mobile中的文檔就緒和頁面事件之間的簡單區別是:
文檔就緒事件用於整個HTML頁面,
$(document).ready(function(e) { // Your code });
當有頁面事件時,用於處理特定的頁面事件:
<div data-role="page" id="second"> <div data-role="header"> <h3> Page header </h3> </div> <div data-role="content"> Page content </div> <!--content--> <div data-role="footer"> Page footer </div> <!--footer--> </div><!--page-->
您還可以使用文檔來處理pageinit事件:
$(document).on('pageinit', "#mypage", function() {
});
使用.on()時,它基本上是您正在使用的實時查詢。
另一方面,.ready(根據您的情況)是靜態查詢。 使用它時,您可以動態更新數據,而不必等待頁面加載。 輸入特定值后,您可以簡單地將值傳遞到數據庫中(如果需要)。
在我們輸入數據(帳戶或帖子甚至評論)的表單中,經常使用實時查詢。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.