剛開始使用jQuery Mobile,發現很多問題需要重新考慮,比如腳本加載問題。
在普通html中,如果a.html中有鏈接到b.html,b.html中有類似代碼:
$(document).ready(function() {
alert("hello");
});
則這段代碼可以被正常執行。
而在jQuery Mobile中,這樣做就行不通了,在瀏覽器中直接刷新b.html,則代碼可以正常執行,而從a.html跳轉到b.html時則不會被執行!為什么?
參見:
http://www.cnblogs.com/pinocchioatbeijing/archive/2013/12/08/3463857.html
第一次做用jQuery Mobile做東西,發現一些跟平時的思維習慣不太一樣的。其中這個框架的頁面加載機制便是其中一個。如果不明白其中的奧秘,往往會出現一些讓人摸不着頭腦的怪現象,比如頁面進入后點擊按鈕后Javascript就是不執行,而用F5刷新頁面后又可以正常執行等。
即使我們明白了HTML文件與jQuery Mobile中page概念的區別,也還是不能解決上述問題。當然,了解這個是一個大前提。原來,jQuery Mobile是用Ajax的方式加載所有HTML中的標記data-role="page"的DIV元素中,第一個HTML頁面一般都是完全加載,包括 HEAD
和
BODY
都會被加載到DOM
中,完成后便是鏈接到的其他頁面內容的加載。 第二個HTML頁面只有 BODY
中的內容會被以Ajax的方式加載到頭一個HTML的 DOM中。
並且第二HTML頁面的 BODY
中的內容也並非全部加載,而僅僅是其中的第一個帶data-role="page"屬性的DIV會被加載進去,其余的東西則無緣進入頁面渲染。
直接上代碼,或許更容易讓人明白些:
index.html
<!DOCTYPE html> <html lang="en"> <head> <!-- META TAGS Declaration --> <meta charset="UTF-8"> <title>TEst</title> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0;" /> <meta name="apple-mobile-web-app-capable" content="yes" /> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.css" /> <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.js"></script> <script> $(document).on('pagebeforeshow', '#foo', function(){ alert($('#body-test').html()); }); </script> </head> <body id="body-test"> <div data-role="page" id="portfolio" data-add-back-btn="true"> <div data-role="content" data-theme='c' > <a href="test.html" data-role="button">Go to Bar</a> </div> </div><!-- Page Project #1 --> </body> </html>
test.html
<html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="style/jquery.mobile-1.3.1.css" /> <script src="jquery-js/jquery-1.10.1.js"></script> <script src="jquery-js/jquery.mobile-1.3.1.js"></script> <title>Foobar</title> </head> <body> <div data-role="page" id="foo"> <div data-role="content"> <a href="#bar" data-role="button">Go to Bar</a> </div> </div> <div data-role="page" id="bar"> <div data-role="content"> <p>Bar</p> </div> </div> </body> </html>
好了,再看這篇文章:
http://stackoverflow.com/questions/17403825/link-fails-to-work-unless-refreshing/17403907
他還有另外一篇文章:
http://www.gajotres.net/how-jquery-mobile-page-handling-affects-javascript-executions/
How jQuery Mobile page handling affects javascript execution
For us to understand this situation we need to understand how jQuery Mobile works. It uses Ajax for page loading into the DOM.
First page is loaded normally. Its HEAD and BODY is loaded into the DOM. That content will stay there (unless page is refreshed) to await further content loading. When second page is loaded, only its BODY content is loaded into the DOM, and when I say its BODY content I mean DIV with an attribute data-role=”page” and its inner content.
This may not sound like something problematic, but you should think twice. What if we have several HTML pages and every and each page has something unique, let’s say different javascript intended to be used only during that page execution, not to mention additional CSS files. Everything found in a HEAD of those files are going to be discarded, and its javascript is not going to be executed.
Unfortunately, you are not going to find this described in their documentation. This is either thought to be a common knowledge or they just forgot to mention it.
There are several solutions to this problem; some are good and some are bad, everything should depend on a project architecture.
Intro
This article is an response to my Stackoveflow answer that can be found here.
Solution 1
In your second page and every other page, move your SCRIPT tag into the BODY content, like this:
1
2
3
4
5
6
7
8
|
<
body
>
<
div
data-role
=
"page"
>
<
script
>
// Your javascript will go here
</
script
>
// And rest of your HTML content
<
div
>
</
body
>
|
This is a quick solution but an ugly one.
Working example can be found in my other answer here: Pageshow not triggered after changepage
Another working example: Page loaded differently with jQuery-mobile transition
Solution 2
Move all of your javascript into the original first HTML. Collect everything and put it into a single js file, into a HEAD. Initialize it after jQuery Mobile has been loaded.
1
2
3
4
5
6
|
<
head
>
<
meta
name
=
"viewport"
content
=
"width=device-width; initial-scale=1.0; maximum-scale=1.0; minimum-scale=1.0; user-scalable=no; target-densityDpi=device-dpi"
/>
<
link
rel
=
"stylesheet"
href
=
"http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css"
/>
<
script
src
=
"index.js"
></
script
> // Put your code into a new file
</
head
>
|
At the end of this article, I will describe why this is a good solution.
Solution 3
Use rel=”external” in your buttons and every elements you are using to change page. Because of it, Ajax is not going to be used for page loading and your jQuery Mobile app will behave like a regular web application. Unfortunately, this is not that good solution. If Ajax is not used for page loading, you will loose a lot of functionalities that make jQuery Mobile such a great framework.
1
|
<
a
href
=
"#second"
class
=
"ui-btn-right"
rel
=
"external"
>Next</
a
>
|
Official documentation, look for a chapter: Linking without Ajax.
Realistic solution
Realistic solution would use solution 2. But unlike solution 2, I would use that same index.js file and initialize it inside a HEAD of every possible other page.
Now, you may ask WHY is that?
jQuery Mobile is buggy, and sooner or later there’s going to be an error and your app will fail (including loaded DOM) if your js content is inside a single HTML file. DOM could be erased, and browser or you will refresh your current page. If that current HTML page don’t have javascript initialized inside its HEAD then that web app will not work until everything is restarted.
In the end, when creating a jQuery Mobile application spend some time thinking about a page architecture. If you need a help take a look at my other article where I am discussing secrets of a good jQuery Mobile architecture.
好吧,最后總結一下:
如果多個html,請將第二個頁面的腳本放在第一個page后面,緊跟在page后面,像這樣:
<body> <div data-role="page"> <script type="text/javascript"> $.support.cors =true; $.mobile.allowCrossDomainPages=true; $(document).ready(function() { alert("hello"); }); </script> <div data-role="header" data-position="fixed"> .......