jQuery Mobile 是針對 HTML5+CSS3 行動網頁應用 (mobile web ) 所推出的使用者介面框架 (UI framework), 相當於行動網頁上的 jQuery UI, 與 jQuery 搭配使用, 優雅地解決了行動網頁跨平台問題, 也使程式設計者不再為陽春的 UI 設計而煩惱. 與 PhoneGap 或 jsWaffle, Titanium 等搭配使用更能將行動網頁轉成 App 發布到 Google Play 或 App Store. 以下是關於 jQuery Mobile 的一些基本觀念 :
- jQuery Mobile 並不是行動版的 jQuery, 而是一個以 jQuery 框架為基礎, 用在行動裝置 (手機與平板) 上的跨平台使用者介面系統, 使用時仍然需要匯入 jQuery, 無法單獨使用. 它跟 jQuery UI 一樣都是屬於 UI 層的框架, 可以說是行動版的 jQuery UI.
- jQuery Mobile 並不是一個行動 App 的 SDK, 以 jQuery Mobile 創建的行動網頁程式只能在瀏覽器中執行, jQuery Mobile 並無法將行動網頁編譯成原生的 App 程式, 要藉助 PhoneGap, jsWaffle 等框架與原生程式的 SDK 才行.
以下一邊摘要整理 jQueryMobile 的用法, 一邊進行功能測試.
首先要佈置一下測試環境. 如果只是要建一個行動版網頁, 則使用者一定要連網, 這樣我們什麼都不須要下載, 只要利用 CDN 所提供的框架檔案即可, jQuery 與 jQuery Mobile 的官網都有提供最新的版本 (latest) :
- jQuery CDN :
http://code.jquery.com/jquery-latest.js
http://code.jquery.com/jquery-latest.min.js (壓縮檔)
- jQuery Mobile CDN :
http://code.jquery.com/mobile/latest/jquery.mobile.css
http://code.jquery.com/mobile/latest/jquery.mobile.js
http://code.jquery.com/mobile/latest/jquery.mobile.min.css (壓縮檔)
http://code.jquery.com/mobile/latest/jquery.mobile.min.js (壓縮檔)
我們只需要使用壓縮檔即可, 因為檔案比較小, 第一次存取網站時下載速度會比較快, 而且我們又不是要研究 jQuery Mobile 是怎麼寫的, 現在主要是研究怎麼用而已. 所以網頁的標頭可以這麼寫 :
<head>
<title></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link type="text/css" rel="stylesheet" href="http://code.jquery.com/mobile/latest/jquery.mobile.min.css">
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
<script type="text/javascript" src="http://code.jquery.com/mobile/latest/jquery.mobile.min.js "></script>
</head>
注意第二個 meta 標籤是一個 viewport, 用來宣告顯示內容時的寬度設定與縮放比設定. 其中 width=device-width 表示顯示的內容將佔滿整個螢幕寬度; 而 initial-scale=1 表示預設內容不縮放, 以 1 倍顯示. 如果網頁想禁止使用者縮放, 那麼 initial-scale 就設定為 no 即可.
如果我們將來要把行動網頁透過 PhoneGap 或 jsWaffle 轉成 App, 那麼就不適合使用 CDN 來匯入框架, 因為使用者不一定會連網, 如果要讓 App 離線也可以使用, 那就一定要自備框架檔案. 當然, 如果我們的 App 應用一定要連網才行 (例如有用到 Google Map), 那用 CDN 就行了. 如果要自備檔案, 直接在上面 CDN 的三個壓縮檔超連結上按滑鼠右鍵, 另存新檔到我們的專案目錄下即可 (注意, 它們都是 ANSI 編碼, 最好開啟後另存為 utf-8 格式). 網頁的標頭設定如下 :
<head>
<title></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link type="text/css" rel="stylesheet" href="
jquery.mobile.min.css">
<script type="text/javascript" src="
jquery-latest.min.js"></script>
<script type="text/javascript" src="
jquery.mobile.min.js"></script>
</head>
CDN 提供的框架檔案通常是最近的穩定版本, 如果要試用最新的開發版 (Alpha, beta 或 RC), 就要去
jQuery 官網 與
jQuery Mobile 官網下載. jQuery 目前是 2.0.2 版, 可以在
下載頁最底下找到 minified 的下載聯結, 只下載 jquery.js 檔即可, 不需下載 zip 檔. 而 jQuery Mobile 目前最新版是 1.3.2, 在其
下載頁最底下也可以找到 js 與 css 檔的下載連結 :
#
jQuery 2.0.2 (minified js)
#
jquery.mobile-1.3.2.min.js (full library, ready to deploy)
#
Minified with Default theme: jquery.mobile-1.3.2.min.css (full library, ready to deploy)
在進行測試之前, 還需要準備一個測試工具, 那就是手機瀏覽器的模擬器. Chrome 本身就內建了這個模擬器, 在 Chrome 右上角有一個三條槓, 點一下在出現選單中選 "工具/開發人員工具", 這樣 Chrome 就會分裂成兩個框, 下半部右下角有一個齒輪, 按下去就會出現設定單, 在 General 項目中,
請務必勾選 Disable cache 這一項, 否則我們對網頁程式所做的改變可能無法馬上呈現 (因為都看到瀏覽器 Cache 的舊網頁), 如下圖 :
其次, 切到 Override 項目, 請勾選 Enable (啟動模擬器) 與 User Agent 這兩項, 選擇要模擬的瀏覽器, 例如 iPhone-iOS6, 再勾選 Device Metrics 後, 按 F5 重新載入網頁即可 :
詳細操作說明可以參考
香腸炒魷魚網站 的介紹. 或者可以安裝 Chrome 應用程式 Window Resizer :
#
https://chrome.google.com/webstore/detail/window-resizer/kkelicaakdanhinjdeammmilcgefonfh
安裝後 Chrome 右上角三條槓控制按鈕左邊會出現一個按鈕, 點一下可以設定瀏覽器視窗大小 :
除了 Chrome 以外, Firefox 也有模擬手機瀏覽器的外掛, 但我建議下載
Opera Mible Emulator (需安裝), 因為這樣可以在獨立視窗測試, 不用去改 Chrome 設定, 而且 Opera 對 HTML5 的支援也不輸 Chrome.
jQuery 與 jQuery Mobile 框架檔案準備妥當後, 便可以撰寫 HTML5 檔案來測試 jQuery Mobile 所提供的功能了. 首先介紹 jQuery Mobile 的架構, 它採用 page view 方式來呈現行動網頁或 App 畫面, 並利用 HTML5 的 dataset 來控制 UI 的呈現. 如下為一單頁結構範例 :
<section
data-role="page">
<header
data-role="header">
<h1>頁頭</h1>
</header>
<article
data-role="content">
<p>內容</p>
</article>
<footer
data-role="footer">
<h3>頁尾</h3>
</footer>
</section>
其中 section, article, header, footer 等標籤都有一個 data-role 屬性, jQuery Mobile 利用 HTML5 的 dataset 新規格, 制定了一系列的 data-xxx 屬性來為我們的原始網頁 "修改門面", 將原始網頁加上一堆樣式類別 (style class) 來把網頁改頭換面, 變成美美的行動網頁. Dataset 屬性是 W3C 在 HTML5 中訂定的客製化資料屬性 (custom data attributes), 允許我們為 HTML 標籤自訂屬性. 所以別誤以為 data-role 是 HTML5 的屬性, 那是 jQuery Mobile 所定義的.
注意, 不一定要使用 HTML5 的語意標籤, 如果把 HTML5 的語意標籤 section, header, article, footer 全部使用 div 也是可以的, 但一堆 div 會讓人看得眼花'撩亂, 所以還是採用語意標籤為宜.
以上將 jQuery Mobile 測試所需之環境安排好後, 便可用下列單頁範本開始測試其各項功能 :
單頁範本
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link type="text/css" rel="stylesheet" href="jquery.mobile.min.css">
<script type="text/javascript" src="jquery-latest.min.js"></script>
<script type="text/javascript" src="jquery.mobile.min.js"></script>
</head>
<body>
<section data-role="page">
<header data-role="header">
<h1>頁頭</h1>
</header>
<article data-role="content">
<p>內容</p>
</article>
<footer data-role="footer">
<h3>頁尾</h3>
</footer>
</section>
</body>
</html>
關於此 template 架構有三點必須要注意 :
- 上述 header, content, footer 三段結構並非必要, 每一個都是 optional, 有些應用程式可能不需要 footer, 有的則 header 與 footer 都不需要, 端視功能設計而定.
- 屬性 data-role="page" 只有在多頁面時才需要, 在單頁情況下可以省略, 但在多頁情形下則一定要有, 否則會顯示全部頁面.
- jQuery Mobile 框架檔案必須在 jQuery 框架與自行撰寫的 Javascript 檔之後匯入.
範例一就是上述單頁範本的實際測試連結 :
測試範例 1 : http://tony1966.xyz/test/jquerymobile/template.htm [看原始碼]
以 Opera 模擬器瀏覽結果如下圖, 與直接用手機瀏覽效果類似 :
如果用 Chrome 瀏覽, 這個 header 與 footer 會橫貫整個螢幕, 我們可以利用 Chrome 的 "工具/Javascript 控制台/Element" 來看看到底 jQuery Mobile 幫我們的原始網頁加了哪些料 :
可見原始網頁中多了許多的 ui class, 事實上 jQuery Mobile 是透過
添加樣式類別, 添加元素以及事件三個方式來增強 (enhance) 網頁的 UI 運作. 從上面的單頁範本可知, jQuery Mobile 是以 data-role="page" 屬性來定義一個顯示頁面 (page view), 其內再用 data-role="header" 來定義頁面的頁頭, 用 data-role="footer" 定義頁尾, 而內容則放在 article 元素內, 其 data-role 設定為 content.
多頁控制
一個網頁應用可能需要兩個以上頁面來完成其功能, jQuery Mobile 支援在單一網頁檔案中嵌入多個頁面, 它採用以內部連結 # 為基礎的多頁面瀏覽系統 (hash-based navigation system), 利用 id 屬性與超連結的 hash 可以在多個頁面間切換, 因此每一個頁面都須指定 id 屬性來識別 :
<section data-role="
page" id="
page1">
<header data-role="header">
<h1>第一頁</h1>
</header>
<article data-role="content">
<a href="
#page2">到第二頁</a>
</article>
<footer data-role="footer">
<h3>頁尾</h3>
</footer>
</section>
<section data-role="
page" id="
page2">
<header data-role="header">
<h1>第一頁</h1>
</header>
<article data-role="content">
<a href="
#page1">回第一頁</a>
</article>
<footer data-role="footer">
<h3>頁尾</h3>
</footer>
</section>
實際測試如範例二 :
測試範例 2 : http://tony1966.xyz/test/jquerymobile/two-pages.htm [看原始碼]
範例二中, 原始網頁裡有兩個 section, 其 data-role 都是 page, 表示此網頁有兩個頁面容器 (page container), 其 id 分別為 page1 與 page2, 但是 jQuery Mobile 只會載入第一個 page 加以改造後顯示, 並且在 DOM 中儲存其參考 (此參考在行動網頁作用期間都會一直存在). 其他頁面都不會載入, 直到透過超連結被要求時才會被 jQuery Mobile 載入, 並加以改造後呈現, 成為 active page. 這時第一頁會被隱藏起來 (但不會被消滅). 我們必須在第一頁中擺放超連結或按鈕, 其 href 值設為 "#目的頁面之 id" 方式切換頁面, 例如前往 id=page2 之超連結要設為 href="#page2".
當瀏覽器載入網頁建立 DOM 樹後, jQuery Mobile 框架就會讀取並剖析原始網頁, 拜訪每一個具有 data-role 屬性的元素, 為其所有子元素套上跨平台行動網頁所需之 CSS3 樣式, 以增強 (enhance) 其 UI 效果 (也就是加料啦).
關於 jQuery Mobile 的多頁控制有下列三點要注意 :
- 當一個多頁面網頁文件載入時, 並不是整份文件中的所有頁面都被改造載入到 DOM 中, 而是只有第一個 page 會被 jQuery Mobile 改造後載入到 DOM 中顯示, 我們必須在第一頁中透過超連結的 href="#id" 來切換到其他頁面. 當切換到其他內部頁面時, jQuery Mobile 是以 Ajax 方式載入該頁面內容進行改造後加入到現有的 DOM 中, 並被 Cache 在 DOM 中以加快切換時的反應速度.
- 每一個視圖頁面都必須有獨一無二之 id 屬性, 利用 a 元素的 hash (#) 來切換內部頁面. 如果是切換到外部頁面, 則須指定檔案名稱, jQuery Mobile 會以 Ajax 方式讀取該外部網頁的第一頁, 加以增強後加入目前網頁的 DOM 中 (不是直接載入外部網頁), 例如 :
<a href="file2.htm">到 file2 的第一頁</a>
注意, 不能在網頁檔後面指定頁面 id, 例如 :
<a href="file2.htm#page2">到 file2 的第二頁</a>
- 每一個頁面都可以載入 javascript 檔, 但其作用域 (scope) 只限於該頁面, 其他頁面無法存取此 Javascript 內的變數.
下面範例三與範例四我們來測試兩個網頁檔的頁面切換 :
測試範例 3 : http://tony1966.xyz/test/jquerymobile/file1.htm [看原始碼]
測試範例 4 : http://tony1966.xyz/test/jquerymobile/file2.htm [看原始碼]
上面的 file1.htm 與 file2.htm 內各有兩個內部 page, 每一頁中都有超連結用來切換到其他頁面, 其中可能有些不會動作, 分析如後.
如果用瀏覽器或模擬器開啟 file1.htm, 它會顯示第一頁, 透過超連結的 href="#page1-2" 就可以切換到第二頁, 這沒問題 :
<section data-role="page" id="page1-1">
<header data-role="header">
<h1>file1.htm 第一頁</h1>
</header>
<article data-role="content">
<a href="
#page1-2">到第二頁</a>
</article>
<footer data-role="footer">
<h3>頁尾</h3>
</footer>
</section>
在第二頁中有六個超連結, 按前三個 "回第一頁" 就會切回第一頁, 但做法有些不同, 第一個 a 元素用 #page1-1 指定頁面 id 切回; 第二個與第三個 a 元素使用 data-rel="back" 切回且有給 href="#", 有超連結底線, 其中第三個不給 href 屬性, 所以沒有超連結底線, 三個都能切回第一頁.
第四個超連結 href="file2.htm" 是載入外部網頁, jQuery Mobile 會以 Ajax 方式載入 file2.htm 的第一頁, 並將其改造後加入 file1.htm 的 DOM 裡, 所以看起來像是原來的 file1.htm 被置換了, 事實上不然. 第五個超連結 href="#page2-2" 意圖指定載入 file2.htm 中的第二頁, 但這樣是不會切換的, 因為 jQuery Mobile 並不知道 page2-2 在哪. 即使指定檔名與頁面 id, 如第六個超連結 href="file2.htm#page2-2" 也是不會切換的, 因為 jQuery Mobile 只會載入外部網頁的第一頁.
<section data-role="page" id="page1-2">
<header data-role="header">
<h1>file1.htm 第二頁</h1>
</header>
<article data-role="content">
<a href="
#page1-1">回第一頁</a><br>
<a
href="#" data-rel="back">回第一頁</a><br>
<a
data-rel="back">回第一頁</a><br>
<a href="
file2.htm">載入 file2.htm 第一頁</a><br>
<a href="#page2-2">回 file2.htm 第二頁</a><br> (無動作)
<a href="file2.htm#page2-2">載入 file2.htm 第二頁</a> (無動作)
</article>
<footer data-role="footer">
<h3>頁尾</h3>
</footer>
</section>
現在假定我們按第四個超連結, 這時 jQuery Mobile 會以 Ajax 載入 file2.htm 的第一頁並加入 file1.htm 的 DOM 中後切換至此頁, 但原來 file1.htm 的 page1-1 與 page1-2 仍然存在 Cache 中. 我們先看看 file2.htm 的第一頁內容 :
<section data-role="page" id="page2-1">
<header data-role="header">
<h1>file2.htm 第一頁</h1>
</header>
<article data-role="content">
<a href="
#page2-2">到第二頁</a><br> (沒作用)
<a href="
file2.htm#page2-2">載入 file2.htm 第二頁</a><br> (沒作用)
<a href="
#page1-1">回 file1.htm 第一頁</a><br>
<a href="
#page1-2">回 file1.htm 第二頁</a>
</article>
<footer data-role="footer">
<h3>頁尾</h3>
</footer>
</section>
如下圖所示, 第一個 a 元素為 href="#page2-2" 意圖切換至 file2.htm 的第二頁, 但這不會動作, 因為目前 DOM 內容事實上是由 file1.htm 改造而來, 只是添加了 file2.htm 的第一頁 page2-1 在 DOM 中而已, 所以 jQuery Mobile 並不知道 page2-2 是啥東西. 在第二個 a 元素我們改用 href="file2.htm#page2-2" 指定載入 file2.htm 的 page2-2 仍然無作用, 不會切到 file2.htm 的第二頁, 如上所述, 這 DOM 目前是 file1.htm 的, 僅載入外部網頁的第一頁.
但第三個與第四個 a 元素按下去就會切回 file1.htm 中的 page1-1 與 page1-2 了, 原因是之前從 file1.htm 的第二頁切換到 file2.htm 的第一頁時, 這 page1-1 與 page1-2 被隱藏起來, 但仍存在 Cache 裡, 所以用 href="#page1-1" 與 href="#page1-2" 就可以回到 file1.htm 了.
以上載入 file1.htm 所做的測試結果顯示, 同一文件內的多頁可以自由切換無礙, 但若切換到外部文件, 那麼只能存取到其第一頁內容, 因為 jQuery Mobile 以 Ajax 讀取外部文件時, 它會去搜尋第一個具有 data-role="page" 的頁面容器 (div 或 section 等), 而忽略其他頁面.
現在反過來, 在瀏覽器或模擬器網址列載入 file2.htm (點上面的測試範例四), 這時會顯示其第一頁 (就是上面那張圖, 外觀完全一樣, 但效果不同), 裡面有四個連結, 其中第一個連結 href="#page2-2" 會切換到其第二頁, 第二個連結 href="file2.htm#page2-2" 也是沒問題, 可以切到自己的第二頁, 雖然這裡加了文件名稱 file2.htm, 但檢視 Chrome 的 Network 發現 jQuery Mobile 並沒有重新載入 file2.htm. 而第三個與第四個連結分別是意圖切換到 file1.htm 的第一頁與第二頁, 但皆無作用, 這是因為此網頁之 DOM 是由 file2.htm 文件建立, 裡面沒有 page1-1 與 page1-2 這兩個頁面之故, 存取外部文件需使用檔名 (而且只載入第一頁).
<section data-role="page" id="page2-1">
<header data-role="header">
<h1>file2.htm 第一頁</h1>
</header>
<article data-role="content">
<a href="
#page2-2">到第二頁</a><br>
<a href="
file2.htm#page2-2">載入 file2.htm 第二頁</a><br>
<a href="
#page1-1">回 file1.htm 第一頁</a><br> (沒作用)
<a href="
#page1-2">回 file1.htm 第二頁</a> (沒作用)
</article>
<footer data-role="footer">
<h3>頁尾</h3>
</footer>
</section>
當 file2.htm 切到第二頁後, 顯示如下 :
其中有兩個連結, 第一個 href="#page2-1" 會切回自己的第一頁, 而第二個連結 href="file1.htm" 則是載入外部文件 file1.htm, 按此連結時 jQuery Mobile 會以 Ajax 方式載入 file1.htm 的第一頁, 經過增強後添加到目前的 DOM 中, 但這時按到第二頁就沒作用了, 因為 Ajax 只載入 file1.htm 的第一頁, 因此 jQuery Mobile 並不知道 page1-2 在哪裡.
<section data-role="page" id="page2-2">
<header data-role="header">
<h1>file2.htm 第二頁</h1>
</header>
<article data-role="content">
<a href="
#page2-1">回第一頁</a><br>
<a href="
file1.htm">載入 file1.htm 第一頁</a><br>
</article>
<footer data-role="footer">
<h3>頁尾</h3>
</footer>
</section>
從以上測試可知, 行動網頁若採用單一文件多頁面方式設計, 頁面切換完全由 jQuery Mobile 自動處理, 我們只要在連結上指定 hash 與 id 即可. 這方法好處是各頁面之間切換很快, 網頁載入後即使關閉連線, 網頁程式仍可運作, 缺點是第一次下載時比較費時 (特別是複雜之應用, 單一檔案包含非常多 page 時). 若採用多文件設計, 被載入的外部文件必須使用單頁面設計, 因為 Ajax 只會載入外部文件的第一頁, 其餘頁面都會被忽略. 此法好處是起始下載很快 (首頁不會很大), 缺點是切換頁面需要維持網路接續, 否則 Ajax 會失敗. 此外, 載入外部文件還要特別注意, 其頁面 id 不可以跟目前網頁中的各頁面相衝突.
下面範例五是多文件設計的例子, 由 main1.htm, page-a.htm, page-b.htm, 以及 page-c.htm 四個網頁文件組成, 每一個文件內都只有一個頁面, 裡面的超連結都要求載入下一個文件, 直到最後 page-c.htm 用 #main1 回到首頁 :
測試範例 5 : http://tony1966.xyz/test/jquerymobile/main1.htm [看原始碼]
page-a.htm 原始碼
page-b.htm 原始碼
page-c.htm 原始碼
如果打開 Google Chrome 的 "工具/Javascript 控制台/Network" 觀察, 可發現每點一次外部連結, jQuery Mobile 就用 Ajax 載入目的文件的第一頁, 並加入目前網頁的 DOM 之中 :
另外, 觀察 page-a/b/c.htm 的原始碼可以發現, 這三個檔案並未匯入 jQuery 與 jQuery Mobile 框架檔案, 為何仍能顯示正常的 UI? 原因是 jQuery Mobile 載入外部文件時, 僅僅是去搜尋第一頁的 data-role="page" 區塊, 加入到當前網頁之 DOM 中, 因此有沒有匯入框架都無所謂. 但是若它們被單獨拜訪時就無法顯示 jQuery Mobile 的 UI 功能了, 因此還是加上匯入框架的 markup 為宜.
下面範例六則是單文件設計的例子, 當走訪各頁時, 直接在 Cache 中找到目的頁面後更新 DOM, 因此反應速度較快, 而且在 Chrome 的 "工具/Javascript 控制台/Network" 中也不會出現 Ajax 的載入動作.
測試範例 6 : http://tony1966.xyz/test/jquerymobile/main2.htm [看原始碼]
在上面的頁面切換測試中, 可以發現頁面切換時具有動畫效果, 這是 jQuery Mobile 利用 CSS3 的 transition 屬性做出來的. 事實上, 它提供了六種切換動畫.
總結以上關於頁面的測試, 摘要如下 :
- 作為頁面容器之元素有兩種, 即 div 或 section 元素, 其 data-role 屬性須設為 page.
- 對於 href="other.htm" 這樣的連結, jQuery Mobile 預設會以 Ajax 方式載入該外部網頁, 搜尋其第一頁內容予以增強後加入現在網頁的 DOM 中成為一個頁面, 並切換至此頁面. 但對於 href="#otherpage" 這樣的連結, jQuery Mobile 直接切換到指定頁面.
~未完待續~
2020-09-14 補充 :
在暫停多年之後最近突然對 Web app 設計有了興趣, 當然就用自己最熟悉的 jQuery Mobile 了, 搜尋資料時看到下面這篇值得參考 :
#
基於JQuery Mobile的Web App實踐