mobilebone.js 是鄙人2014下半年個(gè)人開(kāi)源項目代表作。
先容我吹噓一番,反正吹牛又不要交稅。
一句話(huà)功能簡(jiǎn)介
跟傳統網(wǎng)頁(yè)瀏覽的差別僅僅在于無(wú)刷新!
例如,我們?yōu)g覽首頁(yè),首頁(yè)上有個(gè)如下HTML鏈接:
<a href="mocamoca.html">摩擦摩擦</a>
在傳統頁(yè)面,頁(yè)面會(huì )刷新跳轉至 mocamoca.html , 但是,引入 mobilebone.js 后,就是無(wú)屬性滑動(dòng)到 mocamoca.html 頁(yè)面。
OK,我特意用手機拍手機拍了段視頻給大家感受下(視頻中的頁(yè)面為項目中的測試頁(yè)面)(舍不得買(mǎi)iPhone, 測試機為Android)(優(yōu)酷上傳太慢40K/s果斷投奔愛(ài)奇藝了2M/s):
當然,你也可以打開(kāi)自己的手機瀏覽器、或者微信掃描下面二維碼,體驗同時(shí)順便幫忙眾測下,可以評論或者去Github項目issues( https://github.com/zhangxinxu/mobilebone/issues )反饋給類(lèi)問(wèn)題(前后兩個(gè)圖分別是develop和master兩個(gè)分支的測試頁(yè)):


如果你是在手機瀏覽器訪(fǎng)問(wèn)本頁(yè)面,試試直接 點(diǎn)擊這里 感受一番。
Mobilebone項目已經(jīng)發(fā)布到Github上了,項目地址為: https://github.com/zhangxinxu/mobilebone
如果你覺(jué)得此項目很贊,歡迎star, 如果你想參與建設,歡迎fork!
為什么叫Mobilebone?
1. 顧名思意,移動(dòng)骨頭。 mobilebone.js 也確實(shí)人如其名,只做一件事情,移動(dòng)端單頁(yè)切換,所以 mobilebone.js 很輕便,也很靈活,也沒(méi)什么限制,反而鑄就了其強大。

3. 我特意百度谷歌之,恩,沒(méi)人用這個(gè)名詞。Github上也沒(méi)有類(lèi)似名字的項目,于是就是它的,獨一無(wú)二的!
為何想到做Mobilebone?
早在11年移動(dòng)剛興起的時(shí)候,我就折騰過(guò) jQuery Mobile以及Phonegap . 好吧,也就是折騰過(guò),后來(lái)很快就把jQuery Mobile給丟棄了,主要有兩點(diǎn):一是重,而是UI限制太大,只適合個(gè)人項目!但是,其switch切換是挺值得借鑒的。
上個(gè)月,應該是上上個(gè)月,游擊了一個(gè)手Q的項目,做重構稿的時(shí)候,寫(xiě)了個(gè)單頁(yè)切換方法,主要是為了重構稿交互演示。結果被開(kāi)發(fā)直接拿去用了,于是問(wèn)題來(lái)了,此切換方法并沒(méi)有添加Ajax處理,也沒(méi)有history路由處理。以至于最后的實(shí)現代碼不醇厚-用人話(huà)表示就是“亂”。此時(shí),我意識到,應該可以寫(xiě)個(gè)專(zhuān)門(mén)負責單頁(yè)切換的JS組件。加上自己多年的相關(guān)積累,Android2.3這些版本不需要兼容,我覺(jué)得時(shí)機很成熟了。
于是,前后一個(gè)多月,利用業(yè)余時(shí)間,編寫(xiě)、測試與反復優(yōu)化、細節調整,終于發(fā)布了這個(gè)個(gè)人項目。我會(huì )積極在廠(chǎng)內外推廣,農村和城市齊包圍,萬(wàn)一真火了呢!
Mobilebone適用場(chǎng)景
類(lèi)原生APP的過(guò)場(chǎng)體驗,適用于這些場(chǎng)景:
1. Phonegap等類(lèi)似跨移動(dòng)開(kāi)發(fā)平臺,其靜態(tài)頁(yè)面都是index.html, 單頁(yè)面,因此,需要跟原生一樣的過(guò)場(chǎng)體驗。自己幫設計師實(shí)現iOS原型時(shí)候需要。
2. Hybird app開(kāi)發(fā),原生APP內嵌web APP, 為了兩者體驗一致,不至于交互太唐突,也需要無(wú)刷新過(guò)場(chǎng)效果。例如,上面提到的那個(gè)手Q項目。
3. 就算是純粹的移動(dòng)web APP, 使用無(wú)刷新模式也不失為一種不錯的選型策略。
4. 一些高大上的在線(xiàn)幻燈片演示……等
Mobilebone兼容性
mobilebone.js 基于ES5編寫(xiě),應用了部分HTML特性,原生JS,不依賴(lài)任何其他JS框架,不支持Android 2.3及其以下版本,不支持IE6-IE9. 如果這些搓瀏覽器引入 mobilebone.js , 不會(huì )報錯,不影響正常使用。
首先,引入相關(guān)的CSS和JS:
<link rel="stylesheet" href="mobilebone.css">
<script src="mobilebone.js"></script>
此時(shí),就會(huì )有一個(gè)全局的Mobilebone對象,包含一些屬性與方法。
然后,HTML結構有一定的規則。
body page page page
上面規則是什么意思呢?
我們可以看下 mobilebone.css 結構相關(guān)的CSS代碼:

傳統網(wǎng)頁(yè), body 基本上就是頁(yè)面代名詞,滾動(dòng)條多半也是 body 標簽產(chǎn)生。但是,一個(gè)頁(yè)面貌似只能一個(gè) body ,所以,單頁(yè)switch切換主體就不能是 body 元素,于是,降級,以 body 子元素 page 作為每個(gè)頁(yè)面的框架結構,擔當 body 角色。于是,偶們看到的切換效果,就是 page 間的相互糾纏效果。
這種HTML結構與CSS布局的另外一個(gè)好處就是,可以方便實(shí)現兼容的頭部底部固定效果( position:fixed 效果問(wèn)題依然多多)。例如下面這個(gè) base-slide 測試頁(yè)面的HTML結構:
<body> <div id="pageHome" class="page out"></div> <div id="page1" class="page out"></div> <div id="page2" class="page out"></div> <div id="page3" class="page out"></div></body>
.page 對應的元素就是我們的每一個(gè)頁(yè)面,我們可以在此 div 中盡情書(shū)寫(xiě)我們的設計布局。一般而言,要在 page 元素內部再嵌套一個(gè) content 元素,主要為了實(shí)現滾動(dòng)。如果使用 iScroll 滾動(dòng), 無(wú)需定高;如果原生滾動(dòng), content 元素需要有特定高度值。
然后,什么也不用做,頁(yè)面就能進(jìn)入無(wú)刷新切換模式,超贊的有木有。
如果你想做一些設置,直接在引入 mobilebone.js 之后設置就好了。例如下面 Mobilebone.captureLink 的設置:
<script src="mobilebone.js"></script><script>Mobilebone.captureLink = false;</script>
因為,Mobilebone的默認初始化在DOMContentLoaded之后,因此不需要擔心順序問(wèn)題。不過(guò),如果你是頁(yè)面 load 完畢后再以模塊化方式(如seajs~)加載 mobilebone.js ,需要手動(dòng)初始化一下,此時(shí),就要注意順序,初始化在參數設置的前面,如下:
Mobilebone.captureLink = false;Mobilebone.init(); // 初始化 記住,一個(gè)頁(yè)面只能初始化一次,以免文檔事件重復綁定。
所謂基本切換,指的是無(wú)請求,無(wú)延遲的即時(shí)切換。表現為:每個(gè)page在第1次加載完畢后,就已經(jīng)存在頁(yè)面,所謂的切換僅僅是這些page元素的位置變化。
就好比我們使用PowerPoint文件,每次打開(kāi)一個(gè)屁屁踢幻燈片文件,一個(gè)一個(gè)幻燈片頁(yè)面實(shí)際都是已經(jīng)存在的,我們的瀏覽,其實(shí)都是幻燈片頁(yè)面的位置變化,這就是基本切換。
在DOM層面,只有一種情況會(huì )觸發(fā)基本切換, href 值為錨鏈的 a 元素。例如:
<a href="#pageId">
于是,當我們 tap/click 這個(gè) a 元素的時(shí)候,Mobilebone會(huì )自動(dòng)尋找 id 為 pageId 的頁(yè)面,如果此頁(yè)面存在,則發(fā)生切換動(dòng)畫(huà);如果沒(méi)有該頁(yè)面元素,沒(méi)有任何反應,死鏈。
若有興趣,可以 輕戳這里訪(fǎng)問(wèn) 感受基本切換效果。
相反的過(guò)場(chǎng)方向
動(dòng)畫(huà)的方向不可能都是從右往左的,例如,返回,顯然是需要剛進(jìn)入動(dòng)畫(huà)相反,符合正常認知。要實(shí)現,很簡(jiǎn)單,通過(guò)添加 data-rel="back" 就可以了,例如:
<a href="#pageHome" data-rel="back">返回</a> 此時(shí),元素過(guò)新增一個(gè)類(lèi)名 reverse 反方向運動(dòng)。
然而,有時(shí)候,我們無(wú)法確定動(dòng)畫(huà)的方向,例如,固定在底部的導航,如果導航3從導航2過(guò)來(lái),自然是正方向;但如果是從導航4過(guò)來(lái),則要反方向。 data-rel 該如何設置呢?
哈,使用 "auto" 即可,如下:
<a href="#pageHome" data-rel="auto">前進(jìn)還是后退?</a> Mobilebone會(huì )自動(dòng)判別頁(yè)面在舞臺上的位置,智能識別運動(dòng)方向。瀏覽器的歷史記錄前進(jìn)與后退也是采用的 "auto" 判別機制。
此應用可參考 頭尾固定測試頁(yè)面 – test/fixed-header-footer/index.html .
data-rel 控制訪(fǎng)問(wèn)同樣適用于下面的Ajax切換。
實(shí)際項目,可能有10+個(gè)頁(yè)面,顯然是不可能全部一次性載入的,又大又慢,對于流量如金的移動(dòng)頁(yè)面,是損耗也是浪費。所以,頁(yè)面內容還是要一個(gè)一個(gè)加載實(shí)在,這就需要Ajax切換了。
Ajax加載并切換的實(shí)現很簡(jiǎn)單,你不需要做任何操作,就跟傳統的web頁(yè)面一樣就好,使用 href 指向要加載的頁(yè)面地址,例如:
<a href="ajax.html">
此時(shí),當我們 tap/click 這個(gè) a 元素的時(shí)候,Mobilebone會(huì )以Ajax的形式請求 ajax.html 這個(gè)頁(yè)面,返回的數據會(huì )封裝成 page 頁(yè)面,并以指定的過(guò)場(chǎng)動(dòng)畫(huà)載入。是不是簡(jiǎn)單得有點(diǎn)過(guò)分了?沒(méi)錯,所以下面要加點(diǎn)料。
1. Ajax請求參數
既然是Ajax請求,自然少不了請求參數了。Mobilebone中的Ajax借用了jQuery中 $.ajax() 方法的參數命名,主要如下:
var defaults = { url: "", dataType: "", data: {}, timeout: 10000, async: true, username: "", password: "", success: function() {}, error: function() {}, complete: function() {} } <a>元素傳參策略
對于元素,我們是直接通過(guò)屬性設置傳參。有兩種支持的形式,分別為 data-* 和 data-params .
data-* 是指需要傳遞參數,把參數名替換這里的星號(不區分大小寫(xiě)),并賦予參數值。例如:
<a href="ajax.html" data-timeout="30000">
就是設置請求超時(shí)時(shí)間為30秒。
不過(guò)仍有兩個(gè)注意點(diǎn):
href 值正常,則 data-url 地址會(huì )被忽略,依然使用 href 對應地址作為Ajax請求地址。 data-data , 而是 data-formdata . 例如: <a href="ajax.html" data-formdata="c=1&d=1"> data-params 值則是查詢(xún)序列串。因為如果需要自定義的參數過(guò)多,標簽上就會(huì )有很多 data-* 屬性,略啰嗦。于是,可以以查詢(xún)序列串的形式作為 data-params 的值,例如: <a href="ajax.html" data-params="datatype=json&timeout=20000&success=fun_success">
有人可能會(huì )疑問(wèn),如果存在 data-* 和 data-params 沖突情況怎么辦?哈, data-* 優(yōu)先級大于 data-params . 所以,類(lèi)似下面代碼,則最后請求超時(shí)時(shí)間為 30s , data-params 中的 20s 會(huì )被忽略。
<a href="ajax.html" data-timeout="30000" data-params="datatype=json&timeout=20000&success=fun_success">
還有一點(diǎn),不支持 data 參數的序列化使用,請使用上面的 data-formdata . 有興趣可以 輕戳這里 看下如何使用的。
Ajax回調函數
Ajax回調函數有三個(gè),跟jQuery的Ajax請求一樣,分別是 success , error , 與 complete . 分別表示請求成功,請求失敗與請求完成(包含部分失敗情況)。注意,下面開(kāi)始高能了:
<a href="ajax.html" data-success="globalObject.fun.xxx_ajax_success"> 上面的傳參就是上面提到的 data-* 策略,類(lèi)似,錯誤回調,可以使用 data-error 或者 data-params="error=xxx" . 下面問(wèn)題來(lái)了, globalObject.fun.xxx_ajax_success 表示什么意思?
如果使用了上面代碼,只要不是估計瞎搞,在JS的世界里肯定有下面這位兄弟:
window.globalObject = { fun: { xxx_ajax_success: function() {} }}; 意思就是,當請求成功的時(shí)候,執行全局對象 globalObject 下的子對象 fun 下面的 xxx_ajax_success 這個(gè)方法。最后一個(gè)字符串段一定是方法名,否則是不會(huì )有任何執行的。例如:
<a href="ajax.html" data-success="xxx_ajax_success"> 則表示請求成功的時(shí)候,調用全局方法 xxx_ajax_success .
success(response, status) , 其中 response 表示Ajax請求返回的內容,HTML或者JSON. status 這個(gè)參數其實(shí)沒(méi)啥用,返回成功的狀態(tài)碼。其中,默認的 this 上下文是Ajax執行的完整參數們,是個(gè)對象。結構類(lèi)似本小節展示的 defaults 對象。 error(xhr, status) , 其中 xhr 是發(fā)送的請求對象, status 跟上面一樣意思,就不多說(shuō)了。其中,默認的 this 上下文是Ajax執行的完整參數們,是個(gè)對象。與其他兩個(gè)回調有一個(gè)很大的不同,多了個(gè) message 屬性,告知了錯誤原因,如,網(wǎng)絡(luò )掉線(xiàn)、超時(shí)或是是JSON解析異常等。 complete(xhr, status) , 其中 xhr 是發(fā)送的請求對象, status 跟上面一樣意思,就不多說(shuō)了。其中,默認的 this 上下文是Ajax執行的完整參數們。 字符串類(lèi)型返回值
默認返回的是字符串,會(huì )按照HTML字符串處理。
例如,我們請求 ajax.html 頁(yè)面,該頁(yè)面最好是完整的 body > page 結構。因為,就算頁(yè)面JS掛掉,無(wú)法阻止默認鏈接行為,發(fā)生跳轉,也不會(huì )影響可用性。但是,如果請求的是個(gè)動(dòng)態(tài)頁(yè)面,直接返回的是干凈的HTML代碼,如果沒(méi)有 page 元素,則不能含有 html 以及 body 標簽。
因為Mobilebone會(huì )尋找返回HTML中的 page 元素作為頁(yè)面載入;如果沒(méi)有,則會(huì )將返回的所有HTML封裝在自己創(chuàng )建的 page 中。簡(jiǎn)言之,要么返回“完整HTML頁(yè)面代碼”, 要么返回“干凈的HTML片段代碼”。
2. JSON類(lèi)型的請求
由于某些團隊的中間層還沒(méi)成熟,前后端半分離狀態(tài),導致請求得到的數據只能是JSON數據。雖然個(gè)人建議是后臺那邊使用某些框架基直接吐HTML返回,但現實(shí)是骨感的。不過(guò)不要太多擔心,Mobilebone是有考慮過(guò)這種情況的,其暴露了一個(gè)方法名為 Mobilebone.jsonHandle(json) , 專(zhuān)門(mén)用來(lái)處理JSON數據源,需要返回渲染的HTML視圖代碼或者直接就是 page 元素。
支持一個(gè)參數 json , 此參數必須,為Ajax請求返回的JSON數據。于是,你就可以在此處理方法中套用模板,吐出頁(yè)面完整HTML. Mobilebone會(huì )自動(dòng)根據吐出的內容生成頁(yè)面,并以過(guò)場(chǎng)動(dòng)畫(huà)形式載入。
需要注意的是, Mobilebone.jsonHandle 是個(gè)全局的唯一的方法,所以,如果頁(yè)面有多個(gè)JSON渲染,請使用返回的JSON數據的 id 或其他標志量做區分,精準返回HTML數據(也可以自己返回頁(yè)面-不多見(jiàn))(可參考測試頁(yè)面中 Backbone的例子 )。
下面是JSON測試頁(yè)面的例子代碼:
Mobilebone.jsonHandle = function(json) { var page = document.createElement("div"); page.className = "page out"; page.setAttribute("data-title", json.title); page.innerHTML = json.html; return page;}; 簡(jiǎn)單示意,不要太認真。若有興趣,可以 輕戳這里 訪(fǎng)問(wèn)體驗下。
更好的JSON包括HTML加載建議
雖然Mobilebone提供了直接請求JSON數據的方法,并提供了視圖渲染接口。但是,以我個(gè)人經(jīng)驗,對于實(shí)際開(kāi)發(fā),這種實(shí)現策略是不推薦的。我認為更好的實(shí)現方法應該是這樣的。頁(yè)面骨架,也就是page主體,也就是一個(gè)空 div 默認就載入,然后所有的切換都是基本切換,而不是Ajax切換。在切換即將開(kāi)始的時(shí)候(回調),您就可以使用自己,例如Zepto的Ajax方法去請求你需要的JSON數據,做你任何想做的事情,完全沒(méi)有Mobilebone的限制。
頁(yè)面slide是有時(shí)間的,350ms, 這個(gè)時(shí)間點(diǎn)很可就就完成呈現了最終的頁(yè)面。于是,我們看到的就是,一點(diǎn)擊,頁(yè)面slide,slide結束,內容呈現。哇哦哦~~操作感不要太流暢哦!而且技術(shù)上更可控,因為數據請求、處理與Mobilebone完全解耦。
當然,如果就是個(gè)原型頁(yè)面、簡(jiǎn)單的靜態(tài)頁(yè)面,或者是不喜JS的小伙伴,依賴(lài)Mobilebone的Ajax整體請求與呈現策略顯然是最好的選擇,因為,你什么都不需要做~

3. 請求頁(yè)面的緩存機制
默認情況下,Ajax請求的頁(yè)面,如果之前已經(jīng)請求并載入,下次請求時(shí)候,就會(huì )啟用基本切換,也就是直接使用之前的page過(guò)場(chǎng),而不是再次發(fā)起Ajax請求。這就是Mobilebone請求頁(yè)面的緩存機制。但是,實(shí)際開(kāi)發(fā)時(shí)候,有些頁(yè)面數據是需要實(shí)時(shí)更新,不能被緩存的。此時(shí)怎么破?很簡(jiǎn)單,使用 data-reload="true" 即可( ="true" 可缺省)!例如下面代碼演示:
<a href="ajax.html" data-reload> 于是,請求的頁(yè)面就不會(huì )被緩存了,而是不斷的新舊替換。
對了,Mobilebone中的所有Ajax請求都加了時(shí)間戳,也就是只要有請求發(fā)生,基本上都不會(huì )使用瀏覽器緩存。
4. Ajax加載的loading效果
Ajax是個(gè)需要等待響應的過(guò)程,尤其網(wǎng)絡(luò )較差的情況,比如高峰時(shí)段的地鐵。Mobilebone自帶loading效果。
默認情況的loading效果為, 35% 白色半透明全屏遮罩,中間是個(gè)斑斕的菊花旋動(dòng)效果,如下截圖:

此效果對于90%的移動(dòng)開(kāi)發(fā),以及部分的PC頁(yè)面是適用的。但是,應用場(chǎng)景千千萬(wàn),有時(shí)候,我們 loading 可以希望出現在局部,例如,我們點(diǎn)擊的按鈕、或導航上。此時(shí)該怎么辦?對此,Mobilebone也留了一手。很簡(jiǎn)單,使用 data-mask="true" ( ="true" 可缺省)就可以了。如下所示:
<a href="ajax.html" data-mask> 于是,當我們點(diǎn)擊這個(gè)鏈接時(shí)候, loading 相關(guān)的HTML就會(huì )顯示在這個(gè) a 元素中,通過(guò)簡(jiǎn)單的CSS控制,就能實(shí)現我們需要的自定義loading效果了,例如,只覆蓋按鈕,或者菊花在文字后面顯示。如下面兩截圖效果:


若有興趣,可以 輕戳這里 訪(fǎng)問(wèn)體驗下。
對了,插一句:Mobilebone已經(jīng)對Ajax連續點(diǎn)擊可能會(huì )重復請求的問(wèn)題作了處理,大家無(wú)需擔心額外的請求損耗。
5. 避免Ajax加載,使用傳統刷新
Mobilebone默認會(huì )對同域的地址做Ajax請求無(wú)刷新加載。但是,萬(wàn)一人家就是希望要請求呢?以及,雖然跨域,但是人家依然希望使用Ajax請求了(如跨子域而已)。
輪到 data-ajax 屬性出場(chǎng)了。如下代碼:
<a href="ajax.html" data-ajax="false"> // 此情況下也可使用data-rel="external"
于是,點(diǎn)擊上面 <a> 元素時(shí)候,就會(huì )是瀏覽器的刷新跳轉。
如果人家要頁(yè)面上所有的鏈接,或者大部分都是跳轉,總不能一個(gè)一個(gè)設置 data-ajax="false" 吧,哈,Mobilebone提供了一個(gè)全局參數, Mobilebone.captureLink ,只要設置成 false 布爾值,頁(yè)面所有鏈接誒都是傳統可刷新跳轉鏈接。
Mobilebone.captureLink = false;
例如, 測試引導首頁(yè) 就是這么設置的。
事情還沒(méi)有結束。Mobilebone自帶域名判斷技能,如果跨域,默認會(huì )認為是刷新鏈接。但是,XMLHttpRequest 2.0支持Ajax跨域。例如 a.qq.com 下的頁(yè)面請求 b.qq.com , 此時(shí)需要按照Ajax請求來(lái)走,怎么辦?還是 data-ajax , 這回值設置成 "true" 就可以了。
<a data-ajax="true"> 所謂“過(guò)場(chǎng)回調”,就是從牛A頁(yè)面切換到牛C頁(yè)面時(shí)候,觸發(fā)的一些回調函數。
Mobilebone提供了多個(gè)回調接口,以應對各種交互需求。有如下四個(gè):
null , 如頁(yè)面刷新時(shí)候。 onpagefirstinto 含義一致,不贅述。 "into" , "out" 。 animationstart 含義一致,不贅述。 下面問(wèn)題來(lái)了,如何綁定這些回調方法?
OK,跟Ajax參數綁定類(lèi)似,使用自定義屬性。同樣是兩種模式: data-* 和 data-params .
例如下面這個(gè) data-* 模式:
<div id="pageHome" class="page out" data-onpagefirstinto="home" data-animationstart="start">
或者下面這個(gè) data-params 模式:
<div id="page1" class="page out" data-params="animationstart=start&animationend=end"> 模式不是重點(diǎn),重點(diǎn)是函數名關(guān)鍵字。例如 data-onpagefirstinto="home" 表示什么意思呢?
有些類(lèi)似Ajax的回調,但有差別。在默認沒(méi)有任何設置的情況下,Mobilebone會(huì )認為 home 是個(gè)全局函數的名字。于是,會(huì )使用類(lèi)似 window.home() 的形式執行該回調方法。但是,顯然,JS中應該是要盡量避免不必要的全局變量的,對于實(shí)際項目而言,都是全局方法是不實(shí)際的。于是,Mobilebone暴露了一個(gè)可以修改回調主對象的接口, Mobilebone.rootTransition . 例如,你的頁(yè)面有如下對象:
FUN = { home: function(pageInto, pageOut, response) {}, start: function(page, into_or_out) {}, end: function(page, into_or_out) {}}; 則,你就可以設置:
Mobilebone.rootTransition = FUN;
“哎呀,我不想修改全局,只想局部開(kāi)花”,OK,沒(méi)問(wèn)題,使用 root 關(guān)鍵字修改根對象。例如:
<div id="page1" class="page out" data-root="window"> 哈, page1 的回調函數又變成 window 對象下面的啦~ 同樣,支持 data-params 查詢(xún)字符串模式。另外, data-root 也支持對象級聯(lián),可以幫你獲取層級較深的方法。
關(guān)于過(guò)場(chǎng)回調,如有興趣,可 輕戳這里 瀏覽觀(guān)摩體驗。
直接全局設置
有些回調,每個(gè)頁(yè)面發(fā)生過(guò)場(chǎng)的時(shí)候都會(huì )執行,我總不會(huì )每個(gè)頁(yè)面都加一個(gè) data-callback 吧,又累又啰嗦。此時(shí),你可以使用全局回調設置。直接:
Mobilebone.callback = function() {}; 每次有頁(yè)面進(jìn)入都會(huì )執行,此實(shí)例可參考 頭尾固定的那個(gè)例子 。
如果發(fā)生沖突,也就是 data-callback 也存在,則直接覆蓋全局的 Mobilebone.callback 方法。
mobilebone.css 默認只提供了一種過(guò)場(chǎng)效果,就是左右 slide 效果。
如果你希望有更多的過(guò)渡效果。試試外鏈一個(gè) animate.css , 此CSS位置位于Github項目的 test/transition/animate.css , 包含 fade , slideup , slidedown , turn , flow 等多個(gè)過(guò)場(chǎng)動(dòng)畫(huà)效果,然后,添加特定屬性,就可以實(shí)現我們的效果了,很easy!
<link rel="stylesheet" >
于是,我們在page元素上,使用 data-form="xxx" 或 data-params="form=xxx" 指定特定的過(guò)場(chǎng)動(dòng)效。例如, fade 淡入淡出效果:
<div id="page1" class="page out" data-form="fade"> mobilebone.js 可以符合AMD, CMD規范的加載器加載。例如 seajs , 或 requirejs .
用法其實(shí)很簡(jiǎn)單的:
var Mobilebone = require('mobilebone'); 然后,用法基本上就跟平常時(shí)候一樣,除了需要手動(dòng)初始化一下:
// Mobilebone API設置...然后...Mobilebone.init(); 若有興趣,可參考 test/modular-load 中各個(gè)文件的源代碼示意( index.html 使用的是 seajs , require.html 使用的是 require.js )。這里要看代碼,效果沒(méi)啥看頭。
Mobilebone強大的另外一個(gè)體現就是利用HTML5 history API和地址欄融為了一體。
地址欄的前進(jìn)、后退或者刷新都跟傳統網(wǎng)頁(yè)一樣,可以準確顯示對應內容。因此,無(wú)論是Web APP或者Hybird APP,手機上的返回鍵都能很好地操控我們的內容呈現,就跟Native APP感受一樣(文章開(kāi)始的視頻應該有所體現)。
原理
早些年時(shí)候,我直接使用 hash 做路由指向,后來(lái)發(fā)現經(jīng)常會(huì )干擾定位。原因可參考我之前的文章:“ URL錨點(diǎn)HTML定位技術(shù)機制、應用與問(wèn)題 ”。
這里有必要再次感謝下jQuery Mobile. Mobilebone的history處理與jQuery Mobile一樣,路由地址前面加了一個(gè) & 符號,從而解決了錨點(diǎn)定位的問(wèn)題。
當然,從使用者的角度講,這些你都不需要關(guān)心。

mobilebone.js 核心就是切換,其也只做了這一件事情。正是因為這種簡(jiǎn)單與專(zhuān)一,方能體現其強大。如果你想有更豐富強大的功能,你可以很自如地進(jìn)行擴展。
前面的 animate.css 過(guò)場(chǎng)動(dòng)效就是不錯的擴展。當然,不知CSS,JS層面的擴展更具有潛力。
舉個(gè)例子,你希望swipe時(shí)候,頁(yè)面也有過(guò)渡效果,OK,你參考API文檔擴展下就可以了,或者添加鍵盤(pán)控制,實(shí)現類(lèi)似在線(xiàn)幻燈片瀏覽的效果,也是可以的。
在 plugins/ppt 文件夾下面,就有我寫(xiě)的一個(gè)在線(xiàn)幻燈片演示插件,做的事情其實(shí)很簡(jiǎn)單,單擊非鏈接區域,上下左右鍵盤(pán),以及鼠標滾動(dòng),會(huì )讓幻燈片前后播放。
您可以在PC或者pad上 訪(fǎng)問(wèn)該演示頁(yè)面 。
當然,如果你有其他idea, 也能做出其他很精彩的作品。
1. tap/click事件依賴(lài)
該Tips還是蠻重要的!所謂事件依賴(lài),就是,如果瀏覽器大環(huán)境支持 tap 事件(比如使用了含touch events的Zepto.js),則使用 tap 事件來(lái)觸發(fā)一系列的過(guò)場(chǎng)行為,否則就使用 click 事件。然而,大家可能都知道的,在移動(dòng)設備上, click 具有較長(cháng)時(shí)間的延遲,用戶(hù)在操作的時(shí)候總會(huì )有點(diǎn)怪怪的不順暢的感覺(jué)。怎么辦?在這里,我必須鄭重推薦下 fastclick.js . 很多小伙伴都在用它,Github上面的star要奔萬(wàn)的節奏去了, https://github.com/ftlabs/fastclick .
直接引入 fastclick.js ,然后如下代碼綁定:
FastClick.attach(document.body);
然后我們就能愉快地在移動(dòng)設備上玩耍啦!此js對Mobilebone很友好,有種千年好基友的感覺(jué)。在 test/complex 演示的模擬微信交互頁(yè)面上就使用了 fastclick.js .
getParentElementByTag 方法,根據標簽尋找匹配的父元素,沒(méi)有返回 null . queryToObject 方法,可以把查詢(xún)字符串轉換成對象。 
見(jiàn)下面表格,顏色淡的就是表示不常用的,正常顏色的是可以關(guān)注的:
| API名稱(chēng) | 類(lèi)型 | 默認值 | 示例 | 吐槽 |
|---|---|---|---|---|
| Mobilebone.support | 布爾值 | - | - | 是否兼容Mobilebone, 只讀,親,只讀 |
| Mobilebone.VERSION | 字符串 | - | - | 當前mobilebone.js的版本號,只讀,注意了,只讀 |
| Mobilebone.autoInit | 布爾值 | true | Mobilebone.autoInit = true | 是否DOM加載完畢后自動(dòng)初始化,默認為true. 如果頁(yè)面加載完畢之后的require加載,此值失效,按false處理。 |
| Mobilebone.captureLink | 布爾值 | true | Mobilebone.captureLink = true | 是否捕獲頁(yè)面上的a標簽,執行無(wú)刷新過(guò)場(chǎng)效果。此為全局設置,影響整個(gè)頁(yè)面。默認為true |
| Mobilebone.rootTransition | 對象 | window | Mobilebone.rootTransition = window | 過(guò)場(chǎng)回調方法的根對象。默認是全局window. |
| Mobilebone.classPage | 字符串 | "page" | Mobilebone.classPage = "page" | page元素的標志類(lèi)名 |
| Mobilebone.classMask | 字符串 | "mask" | Mobilebone.classMask = "mask" | mask元素的標志類(lèi)名 |
| Mobilebone.pushStateEnabled | 布爾值 | true | Mobilebone.pushStateEnabled = true; | 是否啟用歷史記錄。此參數我是沒(méi)有想到需要使用的理由,但總感覺(jué)可能用到,于是就放著(zhù)。 |
| API名稱(chēng) | 類(lèi)型 | 返回類(lèi)型 | 參數 | 示例 | 吐槽 |
|---|---|---|---|---|---|
| Mobilebone.transition(pageInto, pageOut, back, options) 或者 Mobilebone.transition(pageInto, pageOut, options) | 函數 | - | pageInto pageOutnull . backoptionsid 和 response . | Mobilebone.transition(element); Mobilebone.transition(element1, element2); Mobilebone.transition(element1, element2, true); Mobilebone.transition(element1, element2, { id: “only” }); Mobilebone.transition(element1, element2, true, { id: “only” }); | 此API在插件擴展的時(shí)候應該是最常用的。此方法為Mobilebone切換的核心。含緩存機制、事件回調觸發(fā)等。 |
| Mobilebone.getCleanUrl(trigger, url, params) | 函數 | 字符串 | trigger <a> 元素??蛇x參數,和 url 至少一個(gè)存在。 urltrigger 有合法 href 值,此參數醬油??蛇x參數,和 trigger 至少有一個(gè)有效。 params | Mobilebone.getCleanUrl(elementOfA); Mobilebone.getCleanUrl(elementOfA, ”, “a=1&b=2″); Mobilebone.getCleanUrl(null, “xxx.html”); Mobilebone.getCleanUrl(null, “xxx.html?a=1&b=2″); Mobilebone.getCleanUrl(null, “xxx.html”, “a=1&b=2″); | 獲得干凈完整的Ajax請求地址?;旧?,此函數API內部用得多,大家大可不必關(guān)心。 |
| Mobilebone.getPage(children) | 函數 | DOM元素或null | children | Mobilebone.getCleanUrl(childElement) | 根據子元素獲取當前所在的page元素。 |
| Mobilebone.createPage(dom_or_html, element_or_options, options) | 函數 | - | dom_or_html element_or_options<a> 元素, page 元素,也可以是第3個(gè) options 參數。 optionsresponse 返回數據。 | Mobilebone.createPage(pageDom); Mobilebone.createPage(generalDom); Mobilebone.createPage(‘<div class=”page out”>xxx</div>’); Mobilebone.createPage(‘<p>xxx</p>’); Mobilebone.createPage(pageDom, triggerLink); Mobilebone.createPage(pageDom, { reponse: ‘<div…>’ }); Mobilebone.createPage(pageDom, triggerLink, { reponse: ‘<div…>’ }); | 重要API. 直接根據DOM或者HTML字符串創(chuàng )建頁(yè)面,并載入。別看API名字較長(cháng),好像很復雜,其實(shí)很簡(jiǎn)單滴。 |
| Mobilebone.getFunction(keys) | 函數 | 對象 或 函數 | keys window.a.b.c 這個(gè)對象,才能執行與調用。 | Mobilebone.getFunction(“a.b.c”) | 此API內用,大家很少會(huì )用到,不要太關(guān)心。 |
| Mobilebone.ajax(trigger_or_options) | 函數 | - | trigger_or_options <a> 元素或者Ajax請求參數對象。必須參數。 | Mobilebone.ajax(document.querySelector(“a”)); Mobilebone.ajax({ url: ‘xxx.html’, success: function() {} }); | 很重要,應該會(huì )比較多用到的API,大家需要留意。 |
| Mobilebone.isBack(page_in, page_out) | 函數 | 布爾值 | page_in page_out | - | 此API沒(méi)什么機會(huì )使用的,內用居多,不必太在意。 |
| Mobilebone.jsonHandle(json) | 函數 | DOM元素 或 HTML字符串 | json | - | 此方法JSON請求必用。全局方法,因此,如果存在多個(gè)JSON需要處理的情況,請使用JSON數據中特定的標志量進(jìn)行區分,例如,返回個(gè) id . 如: { "id": "homePage" , "data": [] } 和這個(gè): { "id": "listPage" , "data": [] } |
| Mobilebone.init(); | 函數 | - | - | - | 初始化方法。默認DOM載入完畢會(huì )執行,無(wú)需關(guān)心。如果 Mobilebone.autoInit 為 false , 或此方法在頁(yè)面 load 完畢后動(dòng)態(tài)載入,則需要手動(dòng)初始化。 |
| Mobilebone.handleTapEvent(event) | 函數 | - | - | - | 起初我只是為了排版好看才將此方法暴露出來(lái)的。后來(lái)發(fā)現,某些場(chǎng)景還是可以用到的。比方說(shuō)你做了某些操作,直接把 click 給永久消滅了,然后使用自己的自定義tap方法,此時(shí)就可以類(lèi)似這樣處理: document.body.addEventListener('myCustomTapEvent', Mobilebone.handleTapEvent, false); 來(lái)綁定過(guò)場(chǎng)效果。 |
一分耕耘一分收獲,終于趕在月底前把這篇文章發(fā)布了,扳一扳手指頭,快40天去了,鮮有項目做這么長(cháng)時(shí)間。來(lái)鵝廠(chǎng)目前最大的收獲之一就是做產(chǎn)品的態(tài)度,一定要花足夠的精力去精雕細琢,kill每一個(gè)痛點(diǎn),完善每一個(gè)體驗。雖然過(guò)程很辛苦,但是做出來(lái)的東西大家會(huì )都喜歡??瓷先ズ孟裾l(shuí)到知道,做產(chǎn)品要用心,但事非經(jīng)過(guò)不知難,一定要親歷與感悟,才能真正成為自己所得之物。
雖然上面調侃多次“說(shuō)不定回火”,但自己實(shí)際并沒(méi)有真在意。我并不確定有多少人會(huì )使用mobilebone.js, 但是,唯一我確定的是,心有多大,舞臺就有多大,如果沒(méi)有制作精品的態(tài)度,沒(méi)有完成世界top級作品的胸懷,沒(méi)有用心的反復雕琢與實(shí)踐,一定是不會(huì )火的,最多就是發(fā)布時(shí)候眾人捧個(gè)場(chǎng)、鼓個(gè)掌,然后,就沒(méi)有然后了,就像千千萬(wàn)萬(wàn)曇花一現的小企業(yè)一般。
所以,細心的你可能發(fā)現, mobilebone.js 中的注釋都是英文的,且API用法,參數,示例都放上面了;提示信息也是蹩腳英文,ReadMe.md也有英文介紹。當下,雖舉目三尺皆白壁,但心在壁外三萬(wàn)里。用人話(huà)表示就是,雖然我身處一個(gè)小屋子,但我希望我做的東西能夠漂洋過(guò)海得到肯定。因此,花了很多額外的功夫做了些國際化的工作,萬(wàn)一哪個(gè)老外慕名前來(lái),也不會(huì )因為看不懂中文文檔而放棄。
謀事在人成事在天,做好自己能夠最好的一切,期待理想之花靜靜綻放。恩,至少,我自己用起來(lái)是很順手的!
希望大家多多支持,共同建設,提出問(wèn)題或提供建議!

回頭,如果大家關(guān)注度不錯,我會(huì )申請個(gè)相關(guān)域名,把此項目獨立出去……一切才剛剛開(kāi)始……
本文為原創(chuàng )文章,會(huì )經(jīng)常更新知識點(diǎn)以及修正一些錯誤,因此轉載請保留原出處,方便溯源,避免陳舊錯誤知識的誤導,同時(shí)有更好的閱讀體驗。
(本篇完)
聯(lián)系客服