杜燕忍,葛華勇,王龍
?。|華大學(xué) 信息科學(xué)與技術(shù)學(xué)院,上海 201620)
摘要:Lizard是針對(duì)目前前端開源框架中存在的不足,由攜程研發(fā)出的適用于無線移動(dòng)端開發(fā)的框架。Lizard Web App是運(yùn)行在瀏覽器上的單頁應(yīng)用,所有加載資源都放在一個(gè)html文件上,所有的用戶交互都交給JavaScript,所有的通信都交給Ajax。該文基于Lizard框架實(shí)現(xiàn)Hybrid App(混合模式移動(dòng)應(yīng)用)的開發(fā),并針對(duì)框架中本地存儲(chǔ)方式進(jìn)行改進(jìn),由此提出了擴(kuò)展store的存儲(chǔ)方式。以多態(tài)方式封裝store,由LocalStorage、IndexDB、SQLite by App替換cookie,進(jìn)而支持多種本地存儲(chǔ)方式,該文只是針對(duì)其中一種方式即LocalStorage進(jìn)行封裝,以提高攜程業(yè)務(wù)開發(fā)效率。
關(guān)鍵詞:Lizard;Hybrid App;JavaScript;Web App;HTML;Ajax;數(shù)據(jù)存儲(chǔ)方式;無線移動(dòng)端開發(fā)
0引言
近年來國內(nèi)外對(duì)Native App取得了很多重要的研究成果,但是對(duì)Hybrid App研究還比較少?;旌夏J揭苿?dòng)應(yīng)用(Hybrid App)是指介于Web App與Native App這兩者之間的App[1],它雖然看上去是一個(gè)Native App,但只有一個(gè)UI WebView,里面訪問的是一個(gè)Web App,它具有Native App良好用戶交互體驗(yàn)的優(yōu)勢(shì)和Web App[2]跨平臺(tái)開發(fā)的優(yōu)勢(shì)。
隨著HTML5[34]可通過手機(jī)瀏覽器運(yùn)行,而不直接依賴于手機(jī)操作系統(tǒng),并且現(xiàn)在各大手機(jī)瀏覽器均支持HTML5[5];Mobile phone中框架的發(fā)展(例如PhoneGap)也為Web App的發(fā)展提供了契機(jī)。主流的Hybrid方案分成三種:以PhoneGap[6]為代表,以WebView作為用戶界面層,以Javascript[78]作為基本邏輯,與中間件通信,再由中間件訪問底層API的方式進(jìn)行應(yīng)用開發(fā);以Titanium為代表,通過對(duì)開發(fā)者提供友好的開發(fā)工具,并折中地把這種開發(fā)語言轉(zhuǎn)換成原生語言,最終打包出整個(gè)應(yīng)用;以Three20為代表,在開發(fā)原生應(yīng)用的基礎(chǔ)上,嵌入WebView,但是整體的架構(gòu)使用原生應(yīng)用提供。在攜程無線[9]的Hybrid框架中,一開始就選擇了PhoneGap方案,未來攜程App會(huì)成為一個(gè)平臺(tái)。
本文基于Lizard框架[10]實(shí)現(xiàn)Hybrid App的開發(fā),針對(duì)原有框架中的本地存儲(chǔ)方式和第三方框架的引用進(jìn)行改進(jìn)和優(yōu)化,并對(duì)改進(jìn)的方法進(jìn)行實(shí)際項(xiàng)目開發(fā),結(jié)果與改進(jìn)之前的結(jié)果一樣符合開發(fā)項(xiàng)目的要求,驗(yàn)證了本方法的有效性。
1Ctrip Wireless H5整體架構(gòu)圖
H5整體架構(gòu)圖如圖1所示。由整體框架可知,無線H5基礎(chǔ)框架主要包含以下部分,各業(yè)務(wù)模塊需按要求對(duì)以下部分進(jìn)行統(tǒng)一引用。
(1)第三方框架:zepto、backbone、require、understore等需要統(tǒng)一引用。
(2)核心框架:Common.js,提供最基礎(chǔ)的UI、網(wǎng)絡(luò)通信(ajax)、數(shù)據(jù)存儲(chǔ)(cookie)等基類,以及UI組件、Widget組件、HybridAPI等組件,需要統(tǒng)一引用。
(3)H5公共基礎(chǔ)樣式:Main.css,提供最基礎(chǔ)和公共樣式,需要統(tǒng)一引用。
(4)H5公共業(yè)務(wù)組件:各類通用的業(yè)務(wù)組件,比如常旅客、常用地址,需要統(tǒng)一引用。
(5)H5公共業(yè)務(wù)模塊攜程(登錄/注冊(cè))、支付等業(yè)務(wù)模塊,需要統(tǒng)一引用。
2Lizard框架
2.1框架簡介
Lizard框架架構(gòu)如圖2所示,Ctrip.H5.Lizard主要由4個(gè)模塊構(gòu)成:第三方框架、核心框架、公共組件庫、業(yè)務(wù)組件庫。
?。?)第三方框架:Ctrip.H5.Lizard底層依賴的第三方庫有4個(gè):Zepto、underscore、backbone和Fastclick。
在Mobile端,Ctrip.H5.Lizard會(huì)加載Zepto,在PC端考慮到兼容性的問題,IE內(nèi)核瀏覽器會(huì)采用Jquery,Ctrip.H5.Lizard可以做到對(duì)環(huán)境自適應(yīng)進(jìn)行加載。
Backbone在Ctrip.H5.Lizard是被定制的,其MVC框架中的Model和Controller的內(nèi)容根據(jù)Ctrip.H5.Lizard適用的環(huán)境被復(fù)寫。
Ctrip.H5.Lizard抽取了Fastclick的核心代碼,復(fù)寫了移動(dòng)端的click事件。
?。?)核心框架:Ctrip.H5.Lizard實(shí)現(xiàn)了Web App的基礎(chǔ)功能。
在Javascript[1114]中實(shí)現(xiàn)了面向?qū)ο缶幊?OOP)的基礎(chǔ),封裝了Ajax請(qǐng)求,處理了本地環(huán)境下的跨域訪問,并對(duì)請(qǐng)求做了緩存處理,通過監(jiān)控Hash的變化,實(shí)現(xiàn)View的無縫切換。
(3)公共組件庫:Ctrip.H5.Lizard的公共組件庫涵蓋了UI組件庫和Widget組件庫兩個(gè)模塊組。
UI組件庫以特定的樣式表為基礎(chǔ),定制Ctrip Mobile的UI組件,實(shí)現(xiàn)了各種交互電話、時(shí)間選取等,Widget組件庫提供了功能性組件庫和UI業(yè)務(wù)組件庫。
?。?)業(yè)務(wù)組件庫:Ctrip.H5.Lizard的業(yè)務(wù)組件庫主要包括攜程(登錄/注冊(cè))、支付等業(yè)務(wù)。
2.2Lizard算法流程
Lizard算法流程圖如圖3所示,Lizard渲染數(shù)據(jù)共分成5個(gè)階段:T1~T5。T1:頁面響應(yīng)時(shí)間。此時(shí),用戶通過瀏覽器發(fā)起一個(gè)請(qǐng)求,當(dāng)前VIEW的HTML文件返回index.html給瀏覽器,瀏覽器接收到index.html開始解析,之后瀏覽器請(qǐng)求核心框架JS處理。Lizard.js收到請(qǐng)求,此時(shí)進(jìn)入T2階段,即數(shù)據(jù)通信請(qǐng)求階段。Lizard.js返回核心框架中的JS文件給瀏覽器,瀏覽器收到核心框架中JS傳來的數(shù)據(jù),開始解析Model Config,根據(jù)Config中的API請(qǐng)求SOA數(shù)據(jù),SOA收到瀏覽器的數(shù)據(jù)請(qǐng)求,此時(shí)進(jìn)入T3階段,即數(shù)據(jù)通信接收階段。SOA返回?cái)?shù)據(jù)給瀏覽器,瀏覽器接收到SOA的數(shù)據(jù),此時(shí)T3階段完成,T4階段開始,瀏覽器根據(jù)接收到的SOA數(shù)據(jù),開始解析Template,此時(shí)DOM生成,但是其為隱藏狀態(tài),此時(shí)瀏覽器繼續(xù)發(fā)送請(qǐng)求給核心JS框架,T4階段完成。此階段又可以稱作DOM穩(wěn)定階段。JS中的核心框架收到瀏覽器的頁面邏輯請(qǐng)求開始進(jìn)行處理,此時(shí)進(jìn)入T5階段,即頁面顯示階段。JS返回處理的結(jié)果給瀏覽器,瀏覽器收到結(jié)果顯示DOM,展示頁面,T5階段完成。其中T1~T4又稱作DOM準(zhǔn)備階段,T2~T3稱為通信準(zhǔn)備階段,整個(gè)T1~T5又叫做Onload階段。Onload是Lizard渲染頁面階段中的View生命周期的一部分。
3Lizard Web App 中View的生命周期
首先,View的生命周期與攜程無線Hybrid密不可分,圖3Lizard算法架構(gòu)在一個(gè)Hybrid架構(gòu)的頁面會(huì)有兩部分組成:Head和Content。Head是由App提供的Android/IOS原生組件,對(duì)應(yīng)IOSNavigationBar/AndroidActionBar。Content由App提供的WebView加載H5提供的頁面,H5與App約定將一組API綁定在WebView的Window對(duì)象中。App通過IOS/Android原生方法調(diào)用到Window對(duì)象,執(zhí)行js的方法,這稱之為App Native調(diào)用Web。App實(shí)現(xiàn)對(duì)WebView URL的觀察者模式,H5通過改變URL的哈希值,App會(huì)通過解析哈希值的變化執(zhí)行對(duì)應(yīng)的操作,這稱之為Web調(diào)用App Native。Lizard支持Hybrid模式,而Lizard在對(duì)Hybrid的設(shè)計(jì)中,采用了切面編程的思想。Web與Hybrid最后的產(chǎn)品差異就在于入口文件,在入口文件中,會(huì)去做初始化,判斷當(dāng)前的環(huán)境,然后以當(dāng)前環(huán)境作為參數(shù),配置相應(yīng)的設(shè)置,切換各種服務(wù)在不同環(huán)境下的配置。所以從開發(fā)者的角度來說,不用關(guān)心當(dāng)前的環(huán)境是Web還是App,只需要調(diào)用相應(yīng)的服務(wù)即可,剩下的事情交給Lizard自身就可以。
其次,Lizard中頁面的整體布局代碼如下:
define(['libs', 'cBasePageView'], function (libs, BasePageView){
var viewhtml = '<h1>Hello World</h1>';
var View = BasePageView.extend({
onCreate: function () {
this.MYMel.html(viewhtml);
}
onLoad: function () {
this.turning();
}
onShow: function () {
}
onHide: function () {
}
});
return View;
});
在該代碼中顯示了View的4個(gè)生命周期回調(diào)順序。
onCreate -> onLoad -> onShow -> onHide
(1)onCreate
onCreate是只有在view生成時(shí)才會(huì)調(diào)用的回調(diào)。在這個(gè)回調(diào)中,一般處理View的模板構(gòu)建、初始化數(shù)據(jù)設(shè)置。onCreate只會(huì)在初始化時(shí)候執(zhí)行一次,第二次訪問不會(huì)執(zhí)行。
(2)onLoad
onCreate每次調(diào)用View時(shí)都會(huì)首先調(diào)用的回調(diào)方法。在該回調(diào)中需要處理數(shù)據(jù)請(qǐng)求、View的數(shù)據(jù)綁定、渲染和View的交互邏輯設(shè)置。onLoad的回調(diào)中需要執(zhí)行this.turning()才會(huì)宣告view的加載完成,進(jìn)入到下一個(gè)生命周期onShow,onLoad在每次切換View時(shí)都會(huì)執(zhí)行,一般在onload中進(jìn)行Ajax異步數(shù)據(jù)請(qǐng)求,請(qǐng)求suceess后調(diào)用turning方法從而觸發(fā)onShow事件。
(3)onShow
onShow是新DOM完成渲染之后進(jìn)入頁面的回調(diào),部分依賴頁面渲染之后的業(yè)務(wù)邏輯可以綁定在這個(gè)回調(diào)中,onShow的執(zhí)行時(shí)機(jī)為調(diào)用turning之后,不調(diào)用turning不會(huì)執(zhí)行onShow。
(4)onHide
當(dāng)頁面執(zhí)行了從A頁面跳轉(zhuǎn)到B頁面時(shí),A頁面會(huì)執(zhí)行hide方法,將View A推到后臺(tái)。onHide就是在A推到后臺(tái)之后的回調(diào)。
4改進(jìn)數(shù)據(jù)存儲(chǔ)方式
在一個(gè)應(yīng)用中數(shù)據(jù)的存儲(chǔ)是非常重要的功能,在攜程的應(yīng)用場景中,大量基礎(chǔ)數(shù)據(jù)會(huì)被緩存下來,比如城市列表、用戶使用歷史等信息。在Web 2.0時(shí)代,Web存儲(chǔ)呈現(xiàn)多樣化的趨勢(shì),除了傳統(tǒng)的cookie,HTML5提供了LocalStorage、SessionStorage、ApplicationCache等存儲(chǔ)方案,同時(shí)Chrome還支持IndexDB。cookie操作在前端開發(fā)過程中經(jīng)常遇到,當(dāng)然如果只是用來存儲(chǔ)一些簡單的用戶數(shù)據(jù),還是比較容易的,要做的可能只是設(shè)置cookie名、值、過期時(shí)間等,讀取也只要根據(jù)cookie的名讀取相應(yīng)的cookie值即可。HTML5本地存儲(chǔ)的前身就是cookie,HTML5的本地存儲(chǔ)是使用LocalStorage對(duì)象將Web數(shù)據(jù)持久化在本地。相比較而言,HTML5本地存儲(chǔ)中每個(gè)域的存儲(chǔ)大小默認(rèn)是5 MB,比起cookie的4 KB要大得多。因此,HTML5本地存儲(chǔ)可以看做是加強(qiáng)版的cookie,不受數(shù)據(jù)大小限制,有更好的彈性以及架構(gòu),可以將數(shù)據(jù)寫入到本機(jī)的ROM中,還可以在關(guān)閉瀏覽器之后再次打開時(shí)恢復(fù)數(shù)據(jù),以減少網(wǎng)絡(luò)流量。同時(shí),這個(gè)功能算得上是另一個(gè)方向的后臺(tái)“操作記錄”,而不占用任何后臺(tái)資源,減輕硬件設(shè)備壓力,增強(qiáng)運(yùn)行流暢性,而且存儲(chǔ)和讀取數(shù)據(jù)的代碼極為簡練。因此在Lizard框架中采用了LocalStorage作為解決方案。同時(shí)參考redis在本地實(shí)現(xiàn)了小型的文檔型數(shù)據(jù)庫。
在store中針對(duì)LocalStorage封裝了常用的方法,比如get(tag,oldFlag)獲取已存儲(chǔ)數(shù)據(jù)、getAttr(attrName,tag)獲取已存儲(chǔ)對(duì)象的屬性、set(value,tag,{oldVal})向store中添加數(shù)據(jù)、setAttr(attrName, attrVal,tag)設(shè)置屬性值、remove()移除數(shù)據(jù)存儲(chǔ)、removeAttr(attrName)移除指定對(duì)象的存儲(chǔ)屬性、setExpireTime(time)設(shè)置過期時(shí)間、setLifeTime(lifeTime,override)設(shè)置當(dāng)前對(duì)象的過期時(shí)間。
數(shù)據(jù)存儲(chǔ)的整個(gè)過程如下:
(1)創(chuàng)建storage項(xiàng)目。
(2)cStore模塊的引用:Lizard用cStore模塊封裝了LocalStorage的CURD操作,所以在使用數(shù)據(jù)存儲(chǔ)時(shí),需要引入cStore模塊。Lizard采用require.js作為模塊加載器,所以在使用時(shí)需要顯示申明依賴關(guān)系。引用代碼如下:
define([libs,cBasePageView,cStore], function(libs, BasePageView, Store){ ... });這里顯示調(diào)用了cStore模塊,在回調(diào)的參數(shù)對(duì)應(yīng)的位置中給出store對(duì)象。
(3)Store的繼承:Lizard實(shí)現(xiàn)了Javascript的OOP開發(fā),為代碼的復(fù)用提供了更好的機(jī)制。在Store的一般使用中,推薦將具體的Store繼承于cStore模塊,代碼如下:
var StoreCase = new Base.Class(Store, {
__propertys__: function () {
this.key = STORAGE_EXAMPLE //設(shè)置在LocalStorage中的key值
this.lifeTime = 2D//D代表天,H代表小時(shí),M代表分鐘,S代表秒
}
initialize: function (MYMsuper, options) {
MYMsuper(options);
}
});
Store采用單例模式,所以需要通過StoreCase.getInstance()獲得,即var storeinstance = StoreCase.getInstance()。
(4)Store的增刪改讀:首先設(shè)置view模板,其次進(jìn)行綁定操作。Store提供了3個(gè)接口做綁定操作:讀取Store.read(tag),設(shè)置/更新Store.set({...}),刪除Store.remove()。
(5)設(shè)置數(shù)據(jù)的過期時(shí)間:對(duì)于過期時(shí)間的處理,在內(nèi)部實(shí)現(xiàn)中參考redis的數(shù)據(jù)結(jié)構(gòu),本文設(shè)置了數(shù)據(jù)的過期時(shí)間。在LocalStorage中數(shù)據(jù)結(jié)構(gòu)如下:
"value":{
"inputvalue":"asdfaf"
}
"oldvalue":{
}
"timeout":"2015/12/19 15:38:37",
"savedate":"2015/12/19 15:08:37"
通過對(duì)LocalStorage的封裝,可以直接在開發(fā)時(shí)通過Lizard調(diào)用,使開發(fā)效率更快。
5結(jié)束語
基于Lizard框架的無線開發(fā),是針對(duì)前端開發(fā)人員常用的一些方法、功能、組件等進(jìn)行的一系列封裝,提高了開發(fā)人員的工作效率。本文首先對(duì)Lizard框架的架構(gòu)以及工作原理進(jìn)行簡單闡述,并針對(duì)Lizard框架中本地存儲(chǔ)方式進(jìn)行了優(yōu)化,在store中封裝了對(duì)LocalStorage的讀寫,實(shí)現(xiàn)了在Web上的本地緩存。其次,通過對(duì)LocalStorage的封裝,cookie與store中的LocalStorage兩種本地存儲(chǔ)方式可以同時(shí)使用,更加方便。最后,正如文中所提到的一樣,存儲(chǔ)方式還有很多,諸如IndexDB、SQLite by App等都是以后技術(shù)發(fā)展的需要。
參考文獻(xiàn)
?。?] 萬曉鳳,雷繼棠,易其軍,等.基于Android智能手機(jī)平臺(tái)的AMT監(jiān)測系統(tǒng)的設(shè)計(jì)[J].電子技術(shù)應(yīng)用,2014,40(3):6870.
?。?] 朱華.AJAX在WEB開發(fā)中的應(yīng)用研究[D].哈爾濱:哈爾濱工程大學(xué),2009.
?。?] 陶國榮.HTML5實(shí)戰(zhàn)[M].北京:機(jī)械工業(yè)出版社,2012.
?。?] cyRotel.WEB APP,HYBRID APP與NATIVE APP的設(shè)計(jì)差異[DB/OL].(2013219)[20150825].http://www.uisdc.com/webhybridnativeapp,20141202.
?。?] 劉艷平,俞海英.基于HTML5的Application Cache技術(shù)研究[J].微型機(jī)與應(yīng)用,2015, 34 (20):6466.
[6] PhoneGap.API介紹[EB/OL]. (20000118)[20160105].http://www.phonegapcn.com/docs/zh/cn/.
[7] NICHOLAS.JavaScript高級(jí)程序設(shè)計(jì)[M].北京:人民郵電出版社,2006.
?。?] 徐浩,周德華,廠卓,等.面向多終端適配的移動(dòng)中間件的設(shè)計(jì)與實(shí)現(xiàn)[J].計(jì)算機(jī)科學(xué)現(xiàn)代化,2011(9):6568.
[9] 劉妍.無線產(chǎn)品部的無線技術(shù)標(biāo)準(zhǔn)及指南[DB/OL].(20141208)[20160105].http://conf.ctripcorp.com/display/Wireless/3.HTML5.