可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm diving into writing a mobile app with jQuery Mobile/PhoneGap. I'm using this sample template to start from, which uses HTML/JS to create the pages. Rather than have all the <page>
tags in one single html file, he's got it split up so it's easier to edit.
Since I will have a separate file for each page, what's the best way to include the tempated header/footer? I've only seen it where you need to copy and paste the whole footer->navbar code into each HTML page. This doesn't seem like it should be. For example, if you want to change one menu item, you need to go into each page and change it.
What's the solution that I'm missing?
Maybe I'm just not understanding jQuery Mobile. For example, their sidebar they use for their docs - is that sidebar code copy and pasted onto each page? That doesn't make sense. It's the same idea as the question I'm asking here about the footer.
http://jquerymobile.com/test/docs/pages/page-cache.html
This is what I've got that doesn't seem right (and $.live('pageinit')
isn't working). This HTML is what goes on each HTML page:
<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;">
And the 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>');
}
回答1:
I've been trying to tackle this problem for a few days now and I've gotten really close to the solution. I use the following 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>
And I've created the following functions to load the menu/content using 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;
}
The .trigger('create');
and .navbar();
are the methods required to keep the JQM styling correct, however, there's still one little bug. The position of the menu (which is set using css top: ...px) is sometimes not correct and moves itself to the correct position after the first tap. Really close though!
Edit: By setting #footer
to position: fixed;
the minor bug I mentioned above is gone. Also, it's easy to make a method that calculates the top
(in px) for the #footer
if the position caused by the top
value by JQM is incorrect.
回答2:
Something like this:
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...
}
you could just define the role=footer in the getText and just check to see if it's defined... if not then add it.
回答3:
If you really want to do this properly, you need to look into a js framework like Thorax or JavascriptMVC.
In a JMVC app, you could do this from any view:
<div data-role="page">
<%== $.View('./header.ejs') %>
<div data-role="content">
...
</div>
<%== $.View('./footer.ejs') %>
</div>
jQuery Mobile is really only useful for progressive markup enhancement and styling for mobile devices. For the actual MVC part you need an MVC framework.
The examples for jQuery Mobile are also mostly geared for building mobile web sites which since they fetch pages from a server assume your code reuse is happening server side.
A phonegap app is a whole nother beast since you will be generating these pages on the fly or from local static files. This is were the MVC framework comes in as you would be building your pages using controllers, views, view helpers, and model classes. You tie all that into jQuery mobile by listening to the pagebeforeshow event as shown on the jQm documentation page on scripting pages
回答4:
We haven't found a good way to do this yet either. So we are actually handling this dynamically in our custom js file. Looking for the closing container - and then dynamically appending the footer after the last content div closes.
回答5:
Depends how you load the respective pages.
If you use rel="external" - no AJAX, each page will be reloaded completely.
If you use regular JQM - AJAX, JQM will grab the page and attach it to your existing DOM. Think of your first page as your "anchor" page, which all subsequent pages are added/removed.
In the 2nd case you could specify a data-append-to-all-pages="true" attribute on elements you want to have on every page.
Then just listen to the respective event (pagebeforeshow?) and add elements with the above label to the new page before it's shown. This way elements would only have to be set on the first page and then automatically be added to any subsequent page being pulled in and added to the DOM.
I'm looking into this right now with a login form, which I need on every page outside the login and have to avoid ending up with duplicate input#someID.
EDIT - possible solution
Put the respective element on the first page and add unique attributes, like so:
<div data-role="navbar" data-unique="true" data-unique-id="log">
// full navbar
</div>
All other pages just get the unique element container
<div data-role="navbar" data-unique="true" data-unique-id="log"></div>
Then use this 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();
}
});
});
Of course this would mean you need the unique container on every page. But then you would just carry the content of it along as you traverse through the app. Should work for me and avoid having the same login form 2+ times inside the DOM.
Plus you would be free to edit it's contents for example adding active class.
回答6:
Don't use pageinit, the events that you should listen for are pagecreate and pageshow, pagecreate gets called the first time a page is loaded, but not when you navigate back to the page, e.g. on back button. Whereas pageshow fires everytime a page is shown, so just bind a live listener to the pageshow event for every page where you add your footer (assuming your footer may change, otherwise use pagecreate).
I have a longer example that shows you how to bind to the event properly in another question: https://stackoverflow.com/a/9085014/737023
And yes a great solution is just to use a PHP/CF include, which is what I use instead of JS.
EDIT
My bad, seems pageinit is now used instead of pagecreate (see here), but it still stands that pageshow fires every time a page is shown - so you can use those as you need