Android 2.x 使用 jQuery Mobile 設定 Position:fixed , Select 會無法正常顯示

在 jQuery Mobile 中可以設定 Header 跟 Footer 為 Fixed(這邊有官方文件),不過為了要能夠支援多種裝置效果,這邊的 Fixed 是用 javascript 去控制高度,而不是用 CSS 的 Position:fixed 。下面是有支援 Position:fixed 的裝置對應表。
image
(資料來源)
在 Android 2.x 的版本下,Position:fixed 必須配合 ViewPort  的設定 user-scalable = 0 的情況下才能作用。但是當 Andriod 2.x 的 Position:fixed 作用時,jQuery Mobile 的下拉選單會沒有辦法在 Android 裝置上展開。

重現這個問題

首先到 jQuery Mobile 官網複製官方建議的基本架構

<!DOCTYPE html> 
<html>
<head>
<title>My Page</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0-rc.1/jquery.mobile-1.1.0-rc.1.min.css" />
<script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script src="http://code.jquery.com/mobile/1.1.0-rc.1/jquery.mobile-1.1.0-rc.1.min.js"></script>
</head>
<body>

<div data-role="page">

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

<div data-role="content">
<p>Hello world</p>
</div><!-- /content -->

</div><!-- /page -->

</body>
</html>

加入測試的 Select 下拉選單

<div data-role="content">
<p>Hello world</p>
<select>
<option>Google</option>
<option>Yahoo</option>
<option>Bing</option>
</select>
</div>

加入 Position: Fixed

<div data-role="header" style="position: fixed; width: 100%;">
<h1>My Title</h1>
</div>

加入為了在 Andriod 2.x 能夠啟用 Position: Fixed 效果必須的 user-scalable=0

<meta name="viewport" content="width=device-width, user-scalable=0, initial-scale=1">

使用模擬器顯示畫面

image

接下來點下下拉選單。

image

沒有看錯,除了在邊邊出現藍色邊框證明有點過之外其他什麼事情都沒有發生。

正常情況下應該是會出現下方這張圖片的樣子。

image

要回復正常彈出下拉選單,只要將 position: fixed; 或是 user-scalable=0 移除就可以了。這是因為只要將 user-scalable=0 移除,position: fixed; 就沒有作用了(測試版本是 Android 2.3.1 Flayer)。 順便一提,這兩個版本在 IOS4 ,IOS5 ,Windows Phone7 下都是沒有問題的,IOS4, Windows Phone7 完全不支援 position: fixed;,而 IOS5 則是完全支援。

Demo

下拉選單不正常彈出

image

下拉選單正常彈出

image


Native select Menu no event on Adroid 2.2 or above

利用 ThemeRoller 設計版面

themroller-mobile-logo
我是到前一陣子才發現 ThemeRoller 這個好用到一個不行的工具,調整版面對我來說實在是一個很痛苦的事情,又是哪個東西改個顏色、改個寬度、改個配色,東修西改一半的開發時間都花在這上面了。如果有要用 jQuery Mobile 來開發的人,強烈建議一開始就使用 ThemeRoller
image
一開始進入頁面就可以看到這個編輯器,預設會先有三個空白的 theme 可以做設定,而左側功能列就是有相關的選項可以做選擇,可以看到基本模組都是可以做調整的。在設定完之後只要按下左上方的 Download Theme 就可以做匯出的動作,include 的方法也非常簡單,匯出的時候就有說明了。
image
在右上方輸入 Theme 的自訂名稱,並且在下載之後加入專案當中,也要在頁面中引用,要在 jQuery Mobile 的 js 跟 css 之前。不過有用過  jQuery Mobile 原本就有預設五種 Theme 可以使用,在官網也有介紹,當一加入 ThemeRoller 產生出來的 css 檔案之後,原本的 Theme 效果就會被覆蓋掉了,如果說想要保留原本的預設樣式要怎麼做呢?幸好還有另外一個 import 功能。
image
選擇右上角的 Import Default Theme 就可以載入 jQuery Mobile 預設的範本,不用害怕會覆蓋掉現在已經在運作的 jQuery Mobile ,或是說如果想要預設的樣式還要自己設定,如果已經有 ThemeRoller 匯出的檔案也只要複製 css 直接匯入就可以看到之前修改的結果。
image
image
如果開啟 Inspector 可以直接點選畫面上想要調整的地方,左側功能列表就自動開啟相對應的設定
官方還有另一個 valencia 樣式可以選擇。
image

利用 Swipe Event 控制換頁

image
Carousel 效果是我認為在 Mobile 上面最難處理的部分,大部分的作法都是用一個長條 div 只顯示其中一部份,再用 css : Left 或是 Top 去控制顯示的部分。如果是 jQuery 早期的動畫效果 jquery.animate() 就算是 ipad2 跑起來也是超頓的,唯一的解法就是利用 –webkit-Transform 來做處理。
在 jQuery Mobile 上面預設在換頁的時候就會觸發 –webkit-Transform 來處理換頁的特效(在不支援的瀏覽器上面會直接換頁顯示),但是這邊的特效跟其他 Framework 呈現方式比較不一樣的是在觸控移動的時候 jQuery Mobile Swipe 的方式是當使用者手指移動超過一段距離之後,就觸發 Swipe 事件。其他的 framework 如果有將 touchstart ,touchmove ,touchend 分別做處理的話,就可以在手指移動的同時就做畫面移動的效果,然後在 touch end 手指離開計算距離決定要不要呈現下一頁,抑或是距離不足就停留在原本頁面。jQuery Mobile 目前看起來沒有太重視這一塊,感覺他們的主要目標還是在容易開發、廣泛支援上面。

Swipe Events

基本上 jQuery Mobile 就是讓你很容易套用,所以要取得滑動的事件只要註冊 swipe event 就可以了,jQuery Mobile 利用 javascript 的 touch event 如果長度超過一定距離就觸發 swipe event。

  • 預設在一秒之內移動水平距離超過 30px 而且垂直小於 20px ,就會觸發 swipe 事件。
  • $.event.special.swipe.horizontalDistanceThreshold = 130; 設定 horizontalDistanceThreshold 參數,將原本水平移動距離 30px 改為 130px 之後,他才會觸發 swipe 事件,這邊就是根據測試的習慣來修改,避免因為太容易換造成其實 user 並沒有想要換頁,但是事件被觸發。
  • durationThreshold Swipe 動作要在多少時間下被完成,如果超過這個時間就不觸發 Swipe 事件,預設 1000 (ms)。
  • verticalDistanceThreshold 垂直移動不能超過多少(px)才觸發 Swipe。
  • scrollSupressionThreshold 水平移動超過多少(px)就停止原本垂直滾動。

Example

一開始我先建立一個 js 物件

Site: {
PrePage: { Url: "" },
NextPage: { Url: "" }
}

全網站註冊 Swipe 事件,只註冊一次

$(document).ready(function () {
$.event.special.swipe.horizontalDistanceThreshold = 130;
$(document).bind("swipeleft", function (e) {
$.mobile.changePage(Site.NextPage.Url, { transition: 'slide' });
});
$(document).bind("swiperight", function (e) {
$.mobile.changePage(Site.PrePage.Url, { transition: 'slide', reverse: true });
});
});

在每一頁載入的時候去修改物件的值

$('div:jqmData(role="page")').live('pageinit', function () {
Pru.Site.PrePage.Url = '@(PreviousSibling.Url)';
Pru.Site.NextPage.Url = '@(NextSibling.Url)';
});

這邊我是用 mvc3 Razor 搭配 ASP.NET MVC SiteMap provider 來控制,強力推薦 ASP.NET MVC SiteMap provider 很好用喔。全網站事件我只有註冊一次,如果在每一次 pageinit (pageint 是 jQuery Mobile 事件,ajaxload 新頁面進來觸發) 重複註冊的話,就會變成一次 swipe 換了好多頁。也有考慮過利用 bind unbind 來控制,但是似乎不是很容易,目前感覺上還是用 js 物件操作會比較方便。


jQuery Mobile | jQuery Mobile

jQuery Mobile #2 切換頁面的特效處理

jQuery 只是 plugin 但是 jQuery Mobile 是 Framework ,他在一引用的時候就自動幫你擋掉所有 A.Link 的動作,就是要你照他的規矩來玩。也有內建很多效果在 A.Link 切換頁面的時候來展現。雖然說效果不比 Sencha Touch 或是其他的 Mobile js Framework ,但是 jQuery Mobile 強調的就是多支援,支援度絕對沒有別家比得上,不用再花很多時間去調整各家瀏覽器、各家 OS 還有各家 OS 上的不同瀏覽器,講到舌頭都打結就知道支援度是多麼可怕的東西。

data-transition

<a href="index.html" data-transition="pop">彈出效果</a>

jQuery Mobile 利用 data-transition 來設定不同的效果,有 slide , slideup ,slidedown ,pop ,fade ,flip 都只要設定上去就可以看到效果了。

<a href="/index.html" data-transition="reverse slide" class="上一頁">

Slide 預設是由右方滑入,如果想做左邊一頁的話就是要設定為 reverse slide 。非常貼心的一點是,當套用效果切換頁面的時候,這時候回上一頁也會使用反向的效果來顯示。

data-rel=”dialog”

<a href="/index.html" data-rel="dialog">

設定 dialog 的情況下,連結頁面會用彈出的來顯示,而且彈出不會記錄在瀏覽器的 history 裡面,上下頁就不會切到彈出這頁。

rel=”external”

<a href="/index.html" rel="external">

如果連結的位置是由 http://||https:// 開頭,jQuery Mobile 就不會幫你做任何處理,直接開啟新頁面。但是如果在內部連結可是也不想要 jQuery Mobile 做什麼事的話,就加上 rel=”external” ,假設說新頁面沒有依照 jQuery Mobile 的 Html 規範走的就必須加上,不然再 ajax loading 的時候就會因為判讀不正常出現 error。


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

jQuery Mobile #1 開始建立一個新的 jQuery Mobile 專案

image

這幾天非常的慘烈,奉勸如果有想要進來開發 Mobile Web 的同好,一定要謹慎評估 Framework 的使用,話說最初我也是非常堅持在效果上,如果能做到像 app.ft.com 這種水準的網站,真的是作夢都會笑。不過最終繞了一大圈,我還是又回到了 jQuery 的懷抱。當然有非常多的原因,時程的壓力、擴充性跟可維護性、不過讓我最後下定決心的還是因為客戶希望時程內要能在 windows phone & IE 上正常瀏覽。

雖然百般無奈,但是開始用了 jQuery Mobile 三個小時之後,其實比我想像中的還要好一些。而且最重要的是,我開始懷抱過年可以賴在家看電視的夢想了。

基本 html 架構

<!DOCTYPE>
<
html>
<
head>
<
title></title>
</
head>
<
body>
<
div data-role="page">
<
div data-role="header">
</
div>
<
div data-role="content">
</
div>
<
div data-role="footer">
</
div>
</
div>
</
body>
</
html>

  • 如果要使用 jQuery Mobile 預設會需要這幾個 div 用 data-role 去設定,分別是 page,header,content,footer,有了這幾個 div 預設的動作才會正常,不然會一直呈現鬼打牆狀態,像是超連結點下去沒有反應之類的…。我第一件發現的事情是 jQuery Mobile 把全部 <a> 的動作都吃掉了(如果超連結是 http:// | https:// 開頭的不會,吃掉的是站內連結),預設會取代成 ajax loading 來做換頁的效果。
  • 使用預設的 ajax loading 的時候,載入的頁面也必須包含這幾個 div , jQuery Mobile 在背景做 loading 頁面的動作,然後把 <div data-role=”page”></div> 之間的資料做更新的動作。
  • jQuery Mobile 最大的優點就是他真的在跨瀏覽器上面做了很多的功夫,像是 pushState 還有 webkit transform 這些很不錯但是又有人不支援的功能,都有默默的判斷。如果說將來 Mobile OS 市場愈來愈多人加入戰局的話,考慮使用 jQuery Mobile 的應該也會大增。


jQuery Mobile | jQuery Mobile

Javascript mobile frameworks

最近需要開發一個新的專案,專門為了手機的平台的 Website ,其實基本上就是 Web 但是希望可以做到 App 的效果,可想而知會花很多時間在 Javascript 的部分作調校,每一行 js 都自己 code 就太累了,趕快在準備階段先來找找好用的相關工具。

主要考量的也只有少少幾個方向

1.換頁特效流暢度

既然特地為了 mobile 裝置作開發,當然要能有更好的使用者體驗,雖然說為了跨平台還選擇了 Web 的方式,但是當然是希望能夠做到 App 的效果。

2.相容性

既然說是 Mobile Framework 就不能只有在少數裝置能使用,其他裝置上就算硬體不能做到特效也是必須要能正常瀏覽不破圖。

3.開發便利性以及整合性

希望可以好開發、好維護,大家都是這樣想的吧

jQuery Mobile

JQuery 這就不用說了,就算沒見過豬走路也吃過豬肉,在 Web 上負有盛名的 JQuery 也出了 Mobile 版本的 plugin。不過在實際操作 demo 跟其他 framework 相比之下真的就被比了下去,在特效處理下就差了蠻多的。

image

▲jQuery Mobile 的預設換頁特效,加入 js 之後所有的換頁連結都會被取代

不過在嘗試之中才發現,其實他還是保有了 JQuery 的精神,容易學習,還有支援跨瀏覽器 (jQuery Mobile Supported Platforms)清單真的是非常豪華,為了讓這張清單洋洋灑灑的,jQuery Mobile 可以說是犧牲掉了非常多的東西,值不值得就見仁見智了

Sencha Touch

這套 framework 畫面還有特效流暢度都比 jQuery Mobile 流暢很多,但是缺點就是這套 framework 開發方式已經不太像開發 Web 了,官方範例的頁面完全都是從 js 裡面去動態產生。這大大的增加了從 Web 要入手的難易度,還有一個重點是這套 Framework 大量的使用了 webkit 的 CSS 3 ,所以才能達到這麼好的效果。

因為使用了大量的 webkit css 效果在 Mobile 上面是比 jQuery Mobile 好的多,實際操作流暢程度真的有差,問題就是並不是每一款行動裝置都支援,除了瀏覽器使用 webkit 核心的裝置外,其他裝置上面會連顯示都有問題,或著是安裝了其他種類的瀏覽器在 Mobile 上也會無法正常執行。

DHTMLX Touch

這款基本上特色跟 Sencha Touch 差不多,也是針對 Webkit 作優化,在非 webkit 上面的狀態會比 Sencha Touch 好一些,但是真正要發布的時候還是在 user Agent 排除掉非 webkit 的瀏覽器吧。

jQTouch

為了讓 jQery Mobile 能夠有更好的體驗,所以 jQTouch 幫 jQuery Mobile 加上了 Webkit 部分的效果,主要是針對 iOS 的裝置作的效果。在其他裝置上就不太行了。

Compendium

大部分的 js Framework 都想要能夠達到 navitve app 的效果,一開始要執行 Mobile Web 的時候我也是這麼想的。現在 Mobile 效能確實提升很多,各種 App 也讓我們忘記他的配備等級其實是很差的,要求能跟一般個人電腦一樣的效果其實真的很不容易。所以很多廠商都直接跳進了 CSS 3 之中,即使 CSS 3 的標準還不是各家瀏覽器都有支援。在我看來 jQuery Mobile 跟 Sencha Touch 正好站在天秤的兩端,一邊是號稱支援幾乎全部的 Mobile 裝置,在每一台機器上都得到一樣的體驗,比瀏覽一般網頁好一些些的體驗。另一邊是讓你忘了你只是在瀏覽 Mobile Web,如果你拿的是 iOS & Android。

Reference

用HTML和Javascript開發iPhone/Android原生軟體-Mobile Web App Framework總整理

JQuery Mobile

ASP.NET MVC – MaxLength & MinLength Client 驗證

在 Mvc 的 Model 屬性中有 MaxLength 跟 MinLength 的限制屬性,一般情況像是 [Required] 必填還有 Regex 的限制都可以搭配 jquery.validate 做到 Client 的 javascript 驗證效果。我本來以為 MaxLength 跟 MinLength 應該也可以達到同樣的效果在 Javascript 先行驗證。

image

▲在 Model 加上長度限制

image

▲可是在 View 使用 TextboxFor 產出的 Html 並沒有加入 jquery.validate 的屬性

原本想說會不會是內建的方法沒有支援,但是怎麼想都覺得不太可能,這麼常用的方法,不支援也太不合常理了吧。爬了網路上的文章才發現如果要限制字串的長度的話,需要用 [StringLength] Attribute,才會在 TextboxFor 的時候自動加入 jquery.validate 的屬性。

image

▲需要用 [StringLength] Attribute

image

▲加入了 jquery.validate 需要的屬性

image

▲[StringLength] Attribute 也提供了最小長度的具名參數

image

▲Html Helper 產出的 Html

Reference

MaxLength Attribute not generating client-side validation attributes

http://stackoverflow.com/questions/6801656/maxlength-attribute-not-generating-client-side-validation-attributes

Ajax – 解決上一頁下一頁問題 jquery.history plugin

相信有開發 Ajax 網站的人都有遇到這個問題,在跟後端溝通的時候使用 javascript 來做到 Ajax 效果的確是讓使用者感覺很順暢。但是在想要回到上一步的時候會習慣性點下上一頁,這時候頁面的反應卻不是預期中的。

jquery.history plugin

為了解決這個問題,網路上也有蠻多解決方案的,jquery.history plugin 剛好就是其中一種。其實它的原理也蠻簡單的,在網址列中的 “#” 後面的字串修改瀏覽器是並不會有任何動作的(單純增加一個”#”是回到TOP),其他情況下的修改,瀏覽器都是會重新去 server 上要求一次資料(也有可能在瀏覽器中的 cache 存在就不會重新要求了,但是也算是 reload 的動作),但是瀏覽器還是會記錄網址的變動,可以隨便拿一個網站試試看。所以在這個 plugin 中,利用這個原理他監控每一次網址列”#”後面的變動,當變動的時候就去觸發 javascript 內部的處理程序。

Implement

官網有Demo可以參考,在這邊我是用Asp.Net Mvc3 預設內容來做

image

當然最重要的就是先把 plugin include 進來啦,再來參考官網上面的範例小調整一下

(function ($) {
function loadContent(hash) {
if (hash != "") {
hash = hash.replace(/W/, '');
try {
eval("ajax" + hash + "();");
}
catch (err) { }
}
}

$(document).ready(function () {
$.history.init(loadContent);
$('#menu a').not('.external-link').click(function (e) {
var url = $(this).attr('href');
url = url.replace(/^.*#/, '');
$.history.load(url);
return false;
});
});
})(jQuery);

 

這邊主要分成兩個部分,$(document).ready 還有 loadContent(hash) 在 $(document).ready 的時候設定初始化 history 而且傳入loadContent 這個當作設定控制的 function ,然後設定 $(‘#menu a’).not(‘.external-link’)  click 的時候觸發。loadContent(hash) 這邊傳入的 hash 就是網址列中 “#” 後面的字串。在這邊做法我有小調整,當 #Home/About 的時候我會去呼叫 ajaxHomeAbout() 這個 function ,再從中去處理這邊要有的動作。

 

<li><a href="#Home/About">About</a></li>

function ajaxHomeAbout() {
$.ajax({
url: "/Home/About/Panel",
type: "GET",
data: "",
success: function (html) {
$('#main').html(html);
}
});
}

 

這樣子基本上就有支援了上一頁下一頁的動作。但是也發現了幾個問題。

1.當網址列固定的時候並不會觸發 javascript 動作

可能需要有某個連結是當按下的時候做判斷而執行不同動作,但是在這邊卻沒有觸發到動作,如果這邊執行的狀態是不需要保留的,可以在每一次動作加上一個 guid 然後在 hash 解析的時候再移除掉。

 

var url = $(this).attr('href');
url = url.replace(/^.*#/, '') + "?" + Guid();

 

hash = hash.replace(///g, "");
hash = hash.replace(/?.*/, "");

 

regex 沒有很熟練所以我用了兩次 replace,這樣可以在每次被點擊的時候都確定去執行動作。

如果需要保留狀態的話,就需要改變 href 的值,或是用其他方式經過 hash 去保留才能夠在複製貼上網址列的時候保留狀態。

 

2.有些動作是有相依性的,沒有辦法在複製貼上超連結的時候直接進入

例如說我在 /Home/About 下加入了一個 hidden 的 div ,當我進入之後點下 show 的超連結便會顯示,當下的 url 是 http://localhost/#Home/About/ShowDiv 可是當我重新開一個視窗將網址貼上的時候,他怎麼傻傻地留在 http://localhost/ 的畫面。這個動作必須先執行 #Home/About 再去執行 #Home/About/ShowDiv 才是正確的,這個 plugin 雖然會在 init 的時候去執行 # 後面動作,不過沒有聰明到知道這些動作的相依性。jQuery History Plugin MVC Sample 這邊範例網站有一個範例就是雙層情況下使用 jquery.history 。就是利用拆解字串的方式去實作這個部分。

 

3.當 click 事件的時候,我們可以得到 this 的參數,不過透過 jQuery.history 就取不到 this 參數

這邊的解法應該就是利用 id 或其他屬性來串了,如果整個 this Json 之後傳入 Url 應該會超過預設長度。

4.SEO

大量使用 Ajax 的網站應該都會遇到這個問題,google 有一些建議

Making AJAX Applications Crawlable

http://code.google.com/intl/en/web/ajaxcrawling/docs/getting-started.html

https://docs.google.com/present/view?id=dc75gmks_118gk53qdg6&interval=5&pli=1

Reference

jQuery history plugin

http://tkyk.github.com/jquery-history-plugin/

JavaScript 模式產生 GUID

http://blog.blueshop.com.tw/jeff377/archive/2007/11/07/53275.aspx