2012-02-05 11 views
60

Mi sto immergendo nella scrittura di un'app mobile con jQuery Mobile/PhoneGap. Sto usando this sample template per iniziare, che utilizza HTML/JS per creare le pagine. Piuttosto che avere tutti i tag <page> in un singolo file html, è stato suddiviso in modo che sia più facile da modificare.Creazione di template intestazioni/piè di pagina modello/persistente in jQuery Mobile e PhoneGap

Poiché avrò un file separato per ogni pagina, qual è il modo migliore per includere l'intestazione/piè di pagina temporizzata? L'ho visto solo dove è necessario copiare e incollare l'intero footer-> codice della barra di navigazione in ogni pagina HTML. Questo non sembra dovrebbe essere. Ad esempio, se si desidera modificare una voce di menu, è necessario accedere a ciascuna pagina e modificarla.

Qual è la soluzione che mi manca?

Forse non sto capendo jQuery Mobile. Per esempio, la loro barra laterale che usano per i loro documenti - è quella copia del codice della barra laterale e incollata su ogni pagina? Non ha senso. È la stessa idea della domanda che sto ponendo qui a proposito del footer.

http://jquerymobile.com/test/docs/pages/page-cache.html

Questo è quello che ho che non mi sembra giusto (e $.live('pageinit') non sta funzionando). Questo HTML è ciò che accade in ogni pagina HTML:

<div id="mainFooter" data-position="fixed" data-id="mainFooter" data-role="footer" class="ui-footer ui-bar-a ui-footer-fixed fade ui-fixed-inline" role="contentinfo" style="top: 58px;"> 

E il JS

$.live('pageinit', function (event) { 
    displayFooter(); 
}); 

function displayFooter() { 
    $('#mainFooter').html('<div data-role="navbar" class="nav-glyphish-example" data-grid="d">' + 
     '<ul>' + 
     '<li><a href="#" id="menuitem1" data-icon="custom">Menu Item 1</a></li>' + 
     '<li><a href="#" id="menuitem2" data-icon="custom">Menu Item 2</a></li>' + 
     '<li><a href="#" id="menuitem3" data-icon="custom">Menu Item 3</a></li>' + 
     '</ul>' + 
     '</div>'); 
} 
+8

Non so perché questa domanda non ha più voti positivi, la trovo una delle fessure reali dell'armatura di jquery mobile. – zode64

+0

jQuery Mobile si aspetta che tu faccia l'inclusione/il template sul lato server invece di usare ajax per caricare solo la barra di navigazione o il contenuto (non è solo usato per PhoneGap che conosci). I metodi JQM come .changePage cambiano l'intero HTML della pagina. Quindi se vuoi includere solo la barra di navigazione o il contenuto con ajax ti consiglio di dare un'occhiata alla mia risposta. – bartolsthoorn

+1

sì, questo è ENORME (ed estremamente frustrante) anche per me. Il dirottamento predefinito degli URL di JQM significa fondamentalmente o 1) DRY - DO Ripeti tutto da capo 2) usa un server per fare il tuo include, 3) scrivi brutti hack che irrompono ovunque grazie al modello di markup quasi incomprensibile di JQM 4) cercare di incorporare un framework MVC sopra JQM (sono entusiasta di Angular, ma è una scienza seria) 5) piangere – rmirabelle

risposta

22

Sto provando ad affrontare questo problema da alcuni giorni e mi sono avvicinato molto alla soluzione . Io uso il seguente codice HTML:

<body> 
    <div data-role="page" id="page"> 

     <div data-role="header"> 
      <h1 id="title">Title</h1> 
     </div><!-- /header --> 

     <div data-role="content" id="content"> 
      <p>Loading...</p> 
     </div><!-- /content --> 

     <div data-role="footer" id="footer" data-position="fixed"> 
      <div data-role="navbar" id="navbar"> 
      </div> 
     </div><!-- /footer --> 
    </div><!-- /page --> 
</body> 

E ho creato le seguenti funzioni per caricare il menu/contenuti utilizzando Ajax:

$(document).on('pageinit', "#page", function() { 
    // for example: displayFooter(); 
    loadContent("main"); 
    loadMenu("default"); 
}); 

function loadContent(location) { 
    return $('#content').load("views/content/"+location+".html", function() { 
     $(this).trigger('create'); 
    }); 
} 
function loadMenu(location) { 
    $("#menu").remove(); 
    $("#navbar").remove(); 

    $("#footer").html('<div data-role="navbar" id="navbar">'); 
    $("#navbar").html('<ul id="menu"></ul>'); 

    $("#menu").load("views/menus/"+location+".html", function() { $("#menu").parent().navbar(); }); 

    return true; 
} 

Il .trigger('create'); e .navbar(); sono i metodi necessari per mantenere lo stile jQm corretto, tuttavia, c'è ancora un piccolo bug. La posizione del menu (che è impostata usando css top: ... px) a volte non è corretta e si sposta nella posizione corretta dopo il primo tocco. Davvero vicino però!

Modifica: Impostando #footer a position: fixed; il bug minore che ho menzionato sopra è sparito. Inoltre, è facile creare un metodo che calcoli lo top (in px) per lo #footer se la posizione causata dal valore top da parte di JQM non è corretta.

+0

Hai provato questo nelle pagine a cui stai collegando? Si carica sulla mia pagina indice, ma quando seguo un link ad una delle mie altre pagine, carica il '

+0

@ John, l'idea di questa struttura è che non cambi mai la pagina. Rimani sempre su index.html e gestisci i clic sui link con javascript. Il menu/contenuto html contiene solo l'html che dovrebbe trovarsi all'interno del menu ul # o #content. Per eseguire automaticamente 'loadContent' devi fare' $ ('# content'). On ('click', 'a', clickkedLink); 'e poi' function clickkedLink() {loadContent ($ (this) .attr ('href')); restituisce falso; } '. Indirizza i tuoi attributi href dei tuoi link ('') alla posizione (ad esempio 'href = 'test'' caricherà' views/content/test.html') – bartolsthoorn

+0

In questo modo hai creato il tuo piccolo framework in un modo (sostituisce la funzione changePage di JQM). Dato che JQM è piuttosto lento, sto pensando di usare solo il CSS/markup di JQM e disabilitare il file javascript di JQM. Questo richiede un po 'di lavoro, ma mi piace questa struttura, potendo caricare il menu/contenuto in modo dinamico. – bartolsthoorn

2

dipende da come si caricano le rispettive pagine.

Se si utilizza rel = "external" - nessun AJAX, ogni pagina verrà ricaricata completamente.

Se si utilizza JQM regolare - AJAX, JQM acquisirà la pagina e la collegherà al DOM esistente. Pensa alla tua prima pagina come alla tua pagina "ancora", che tutte le pagine successive vengono aggiunte/rimosse.

Nel 2 ° caso è possibile specificare un attributo di dati-append-to-all-pages = "true" sugli elementi che si desidera avere su ogni pagina.

Quindi basta ascoltare il rispettivo evento (pagebeforeshow?) E aggiungere elementi con l'etichetta sopra alla nuova pagina prima che venga mostrato. In questo modo gli elementi dovrebbero essere impostati solo sulla prima pagina e quindi automaticamente aggiunti a qualsiasi pagina successiva che viene inserita e aggiunta al DOM.

Sto esaminando questo adesso con un modulo di accesso, che ho bisogno su ogni pagina al di fuori del login e devo evitare di finire con # inputID duplicato.

EDIT - possibile soluzione

Mettere il rispettivo elemento sulla prima pagina e aggiungere caratteristiche uniche, in questo modo:

<div data-role="navbar" data-unique="true" data-unique-id="log"> 
    // full navbar 
</div> 

Tutte le altre pagine solo ottenere il contenitore unico elemento

<div data-role="navbar" data-unique="true" data-unique-id="log"></div> 

Quindi utilizzare questo script:

$('div:jqmData(role="page")').live('pagebeforehide', function(e, data) { 

    // check page you are leaving for unique items 
    $(this).find('div:jqmData(unique="true")').each(function(){ 

     // more or less 1:1 stickyFooter 
     var uniqueID = $(this).jqmData("unique-id"), 
      nextPage = data.nextPage, 
      nextUnique = nextPage && nextPage.find("div:jqmData(unique-id='"+uniqueID+"')"), 
      nextMatches = nextUnique.length && nextUnique.jqmData('unique-id') === uniqueID; 

     // if unique items on previous and new page are matching 
     if (uniqueID && nextMatches) { 
      nextUnique.replaceWith(uniqueID); 
      $(this).jqmData("unique-id").empty(); 
      } 
     }); 
    }); 

Ovviamente ciò significa che è necessario il contenitore univoco in ogni pagina. Ma poi ne porteresti il ​​contenuto mentre attraversi l'app. Dovrebbe funzionare per me ed evitare di avere lo stesso modulo di login 2+ volte all'interno del DOM.

Inoltre, si è liberi di modificarne il contenuto, ad esempio aggiungendo classe attiva.

+0

Non riesco proprio a capire perché sembra che questo sia un grosso problema. Perché sembra che il modo "consigliato" sia quello di copiare e incollare il piè di pagina in ogni pagina? Non ha senso. –

+0

Forse non sto capendo jQuery Mobile. Per esempio, la loro barra laterale che usano per i loro documenti - è quella copia del codice della barra laterale e incollata su ogni pagina? Non ha senso. È la stessa idea della domanda che sto ponendo qui a proposito del footer. http://jquerymobile.com/test/docs/pages/page-cache.html –

+1

forse questo è qualcosa che dovresti gestire dal lato server. Penso che CFinclude in coldfusion, ad esempio, in cui basta inserire la stessa barra di navigazione in ogni pagina. – frequent

2

Non abbiamo ancora trovato un buon modo per farlo. Quindi stiamo effettivamente gestendo questo in modo dinamico nel nostro file js personalizzato. Cerca il contenitore di chiusura - e poi aggiunge dinamicamente il piè di pagina dopo la chiusura dell'ultimo div di contenuto.

+0

È una soluzione, ma da quello che ho letto, il problema con questo è che jQuery Mobile non applica tutte le cose che sarebbero necessarie se il footer fosse stato caricato normalmente. –

+0

Non ho provato ma dovresti essere in grado di chiamare una sorta di funzione di creazione che immagino, proprio come facciamo per le visualizzazioni di elenco/pulsanti, ecc. –

2

Non utilizzare pageinit, gli eventi che dovresti ascoltare sono pagacreate e pageshow, il pagecreate viene chiamato la prima volta che viene caricata una pagina, ma non quando si torna alla pagina, ad es. sul pulsante indietro. Mentre pageshow si attiva ogni volta che viene visualizzata una pagina, quindi associa un ascoltatore dal vivo all'evento pagehow per ogni pagina in cui aggiungi il piè di pagina (supponendo che il piè di pagina possa cambiare, altrimenti usi pagecreate).

Ho un esempio più che vi mostra come associare all'evento correttamente in un'altra domanda: https://stackoverflow.com/a/9085014/737023

E sì una grande soluzione è solo quello di utilizzare un PHP/CF includono, che è quello che uso, invece di JS.


EDIT Il mio male, sembra pageinit è ora usato al posto di pagecreate (see here), ma si distingue ancora che pageshow incendi ogni volta che una pagina è indicata - in modo da poter utilizzare quelli di cui hai bisogno

+0

Come ho detto, sto ottimizzando per PhoneGap, il che significa che non posso includi PHP - PhoneGap non consente file .php, solo .html e .js. –

+0

Oh, mi sono perso, quindi basta inserirlo tramite JS - potresti anche usare il plug-in ufficiale di jQuery che è molto carino: http: //api.jquery.it/category/plugins/templates/ –

3

Qualcosa in questo modo:

function getText() { 
    //return footer text here 
} 


$("div:jqmData(role='page')").live("pagebeforecreate",function() { 
    // get find the footer of the page 
    var $footer =$(this).page().find('div:jqmData(role="footer")') 
    // insert it where you want it... 
} 

si può solo definire il ruolo = piè di pagina nella getText e basta controllare per vedere se è definito ... se poi non aggiungerlo.

+0

Da quello che ho letto, il problema con questo è che jQuery Mobile non applica tutte le cose che farebbero se il footer fosse caricato normalmente, no? –

+0

Questo è quello che sto usando e tutte le cose di jqm sembrano essere applicate. Se non sbaglio, markup jqm si verifica qualche volta dopo pagecreate. – bmurmistro

3

Se si vuole veramente farlo correttamente, è necessario esaminare un framework js come Thorax o JavascriptMVC.

In un'applicazione JMVC, si potrebbe fare questo da qualsiasi vista:

<div data-role="page"> 
    <%== $.View('./header.ejs') %> 
    <div data-role="content"> 
    ... 
    </div> 
    <%== $.View('./footer.ejs') %> 
</div> 

jQuery Mobile è davvero utile solo per l'aumento del margine di profitto progressivo e styling per i dispositivi mobili. Per la parte MVC effettiva è necessario un framework MVC.

Gli esempi per jQuery Mobile sono anche principalmente orientati alla creazione di siti Web mobili che, dal momento che recuperano le pagine da un server, presuppongono che il riutilizzo del codice avvenga sul lato server. Un'app di PhoneGap è un vero e proprio bestione dato che genererai queste pagine al volo o da file statici locali. Questo è il caso in cui il framework MVC si presenta come se si costruissero le proprie pagine usando controller, viste, view helper e classi di modelli. Tu leghi tutto ciò a jQuery mobile ascoltando l'evento pagebeforeshow come mostrato nella pagina di documentazione di jQm su scripting pages