移動Web應用開發技術講解-Sencha Touch 1.1
移動應用主要有兩種模式:本地應用和移動Web應用。目前以本地應用最為流行,而移動Web應用也日趨流行。這兩種模式相當於我們經常說的CS架構和BS架構。
本地應用,簡單來說就是通過使用手機作業系統支援的程式語言(例如:iphone的iOS系統使用Objective-C語言,google的android系統則使用Java語言)編寫軟體,然後安裝在手機上的應用軟體。本地應用開發可以直接呼叫手機作業系統的 API(包括UI介面介面、攝像頭介面、加速度感測器介面、讀寫記憶體地址等等),因此響應速度更快、使用者體驗更好(介面可製作得很優雅、操作非常流暢)、不受網路的限制。只是目前手機作業系統眾多:蘋果的iOS、谷歌的Android、微軟的WindowPhone 7、諾基亞的Symbian、其他廠商的WebOS、黑莓等,若一款應用軟體想在不同的作業系統上執行,則需要針對不同的平臺重新開發(有可能還需要根據手機螢幕的大小進行特定設定),這是一件非常痛苦的事情。
簡而言之,本地應用具有可以充分發揮裝置硬體和作業系統的特性,執行效率高,完全不受網路限制的優勢;也具有開發週期較長、成本較高(需要為各種作業系統進行開發)、不同終端的適配度不理想的劣勢。
移動Web應用,簡單來理解就是針對移動終端優化過的Web 站點,終端使用者通過支援Html5、Css3、Javascript標準的Webkit核心瀏覽器訪問部署在伺服器的Web應用。因此移動Web應用具有跨平臺、多種終端的廣泛適配(降低了開發週期和成本)、實時調整與完善、Web開發者可以快速上手等優勢;當然限於手機作業系統的安全限制,移動Web應用還是在硬體功能呼叫方面有所滯後(譬如:目前還不能直接呼叫手機的加速度感測器、攝像頭)、複雜的使用者介面效果難以實現等劣勢。不過,隨著HTML5的不斷髮展,移動Web應用也將更加強大。
1.2 移動Web應用開發框架
目前主要的移動Web應用開發框架有:Sencha Touch、JQuery Mobile以及PhoneGap。下面簡單介紹一下這三個開發框架。
u Sencha Touch:Sencha Touch框架是世界上第一個基於HTML 5的Mobile App框架,它可以讓Web App看起來像Native App。美麗的使用者介面元件和豐富的資料管理,全部基於最新的HTML 5和CSS3的 WEB標準,全面相容Android和iOS裝置。SenchaTouch相對來說是一個重量級的移動Web應用框架,適合用於開發業務邏輯比較複雜的移動Web應用。優點:針對觸控式螢幕豐富的UI設計支援複雜互動、純JavaScript搞定佈局、版本穩定效能尚可。
u JQuery Mobile:JQuery Mobile 是 jQuery 在手機上和平板裝置上的版本,不僅給主流移動平臺帶來jQuery核心庫,而且釋出一個完整統一的jQuery移動UI框架,支援全球主流的移動平臺,它屬於一個輕量級的移動Web應用框架,可以非常便捷的開發出基於Html5的移動網站。優點:超多平臺支援、入門簡單傳統div佈局;缺點:UI支援比較簡單不適合複雜互動。
u PhoneGap:PhoneGap是一個用基於HTML,CSS和JavaScript的,建立移動跨平臺移動應用程式的快速開發平臺。它使開發者能夠利用iPhone,Android,Palm,Symbian,WP7,Bada和Blackberry智慧手機的核心功能——包括地理定位,加速器,聯絡人,聲音和振動等,此外PhoneGap擁有豐富的外掛,可以以此擴充套件無限的功能。PhoneGap是免費的,但是它需要特定平臺提供的附加軟體,例如iPhone的iPhone SDK,Android的Android SDK等,也可以和DW5.5配套開發。使用PhoneGap只比為每個平臺分別建立應用程式好一點點,因為雖然基本程式碼是一樣的,但是你仍然需要為每個平臺分別編譯應用程式。目前PhoneGap缺陷還是蠻多的,比如執行速度慢,UI反應延時。假以時日,隨著技術的發展,問題會得到解決的。
具體選擇那種移動Web框架,需要從專案組人員技術及業務需求情況出發進行選擇:
1、功能簡單,只想讓現有網站支援手機和平板電腦等移動裝置,可考慮jQuery Mobile框架,入門簡單而且支援較多平臺。
2、想做客戶端而且跨平臺、豐富的互動,且專案組有熟悉ExtJS的開發人員,Sencha Touch是個不錯的選擇。
3、如果需要呼叫到手機作業系統的API,可以把Sencha Touch(或JQuery Mobile)與PhoneGap進行整合開發。
Sencha Touch框架是世界上第一個基於HTML 5的Mobile App框架,也是目前為止所發現的最強大的應用於移動平臺的框架,它將自己定位為框架(Framework)而不是類庫(Library),也可以充 分印證這一點。相信隨著Sencha Touch的不斷髮展,移動平臺的Web App使用者體驗設計會得到大幅提升,同時也會對HTML 5和CSS3在移動平臺上的普及推廣產生很大的促進作用。可以預見,隨著HTML 5愈加強大的功能,未來的移動應用將會逐漸向Web App時代邁進。
Sencha Touch是原來的Extjs專案組與jQTouch和Raphael兩大專案強強聯手後,打造的全新Mobile App框架。
Sencha Touch可以讓你的WebApp看起來像Native App。美麗的使用者介面元件和豐富的資料管理,全部基於最新的HTML 5和CSS3的 WEB標準,全面相容Android和iOS裝置。
Sencha Touch官方列出的幾大特性有:
u 基於最新的WEB標準 – HTML 5,CSS3,JavaScript。整個庫在壓縮和gzip後大約80KB,通過禁用一些元件還會使它更小。
u 支援世界上最好的裝置。Beta版相容Android和iOS,Android上的開發人員還可以使用一個專為Android定製的主題。
u 增強的觸控事件。在touchstart等標準事件基礎上,增加了一組自定義事件資料整合,如tap、swipe、pinch、rotate等。
u 資料整合。提供了強大的資料包,通過Ajax、JSONp、YQL等方式繫結到元件模板,寫入本地離線儲存。
在檢視Sencha Touch自帶的Demo以及實際使用中,還可以發現具體不錯的功能點:
u HTML 5地理定位
u 重力感應滾動
u 滾動Touch事件
u 為移動優化的表單元素
u JSONP代理(跨域資料讀取)
u YQL資料代理(類似查詢語言式資料獲取)
u 遮罩彈出層
u Multi-Card佈局
u CSS3 Transitions
u Tab元件以及滾動列表檢視
Sencha Touch的開發環境搭建相當簡單,在Eclipse中建立一個Web專案,定好專案的目錄結構後,引入Sencha Touch的類庫。
Sencha Touch的除錯工具,我主要是使用google的chrome瀏覽器(最新版本是chrome15.0.87),下載地址:http://www.google.cn/Chrome。
按我們的通用平臺架構,檢視層使用了Freemarker模板,因此前臺頁面一般分為ftl檔案和js檔案。根據Sencha Touch的特點以及我自己的思考,一個模組一般只需用一個ftl檔案,然後在這個檔案引入所需用的自定義的js檔案(通用的元件js檔案,可以考慮放入到freemarker模板中)。
以下就是第一個例子的ftl(stFirstExample.ftl)檔案內容:
<@c2.touch title="" cssList=[] jsList=['example/stFirstExample.js']>
</@c2.touch>
cssList是用來引入自定義的css3樣式檔案,jsList是用來引入所需的js檔案。
js(stFirstExample.js)檔案內容:
//建立第一個示例的名稱空間
Ext.ns('example', 'example.views');
//通過Ext.setup方法來參加一個senchatouch應用頁面,setup方法裡可以配置很多屬性
Ext.setup({
statusBarStyle: 'light',
onReady: function() {
//工具欄-toolbar
varfunBar = {
xtype: 'toolbar',
title: 'ST 第一個例子',
dock: 'top', //工具欄放置的位置(必須的屬性):top-上,bottom-下,left-左,right-右
scroll: 'horizontal',
height:30,
items: [{
xtype:'button',
text: '桌面',
ui: 'back',
//iconMask:true,
//iconCls:'home',
style:btStyle,
handler:function(){
window.location = prefix + '/index.action';
}
}]
};
//主介面
varviewport = new Ext.Panel({
fullscreen:true,
monitorOrientation:true,
dockedItems:[funBar],
items:[{
html:'hello kitty......'
}]
});
}
});
可以看到,stFirstExample.js 的第一行程式碼建立了兩個名稱空間:example和example.views。
第二行程式碼呼叫了 Ext.setup() 方法,用以建立一個觸控裝置的 Web 頁面,該方法可以為我們的應用設定不同的啟動屬性和行為:
l icon,設定該應用預設的圖示;
l tabletStartupScreen,該屬性設定在平板電腦上的啟動圖示;
l phoneStartupScreen,該屬性設定在智慧手機上的啟動圖示;
l glossOnIcon,該屬性設定是否在預設圖示上呈現光環效果;
l onReady,該方法會在頁面載入完畢,瀏覽器中的 DOM 模型已經建立完成時被呼叫。由於為了保證程式在執行時所依賴的JavaScript 檔案都已經載入完畢,我們一般將應用啟動的邏輯置於該方法內,類似於 Java 程式的 main 方法。
在onReady方法中,有一個地方我們需用注意的:
l Ext.Panel物件的dockedItems屬性,通過它可以在panel中放置工具欄等元件,可選值有:top-上,bottom-下,left-左,right-右。fullscreen屬性為true(預設為false)則強制該panel充滿整個螢幕。monitorOrientation屬性為true則可以讓panel面板監聽螢幕方向發生變化時候的事件。
l dockedItems屬性裡的物件,必須由docked屬性,用以指定放置的位置。
當然js檔案也可以通過另外一種方式建立應用:
//通過Application來建立一個應用
var FirstApp = new Ext.Application({
name: 'firstApp',
useLoadMask: true,
launch: function () {
//工具欄-toolbar
varfunBar = {
xtype: 'toolbar',
title: 'ST 第一個例子',
dock: 'top', //工具欄放置的位置(必須的屬性):top-上,bottom-下,left-左,right-右
scroll: 'horizontal',
height: 30,
items: [{
xtype: 'button',
text: '桌面',
ui: 'back',
//iconMask:true,
//iconCls:'home',
style: btStyle,
handler: function(){
window.location= prefix + '/index.action';
}
}]
};
//主介面
var viewport = newExt.Panel({
fullscreen: true,
monitorOrientation:true,
dockedItems: [funBar],
items: [{
html: 'hellokitty......'
}]
});
}
});
Ext.Application例項的初始化,意味者一個sencha touch應用的建立,這個類的例項化後,會自動建立一個全域性的變數FirstApp,並且同時建立了如下的名稱空間:
firstApp
firstApp.views
firstApp.stores
firstApp.models
firstApp.controllers
而launch的方法只會執行一次。
在我們的Web應用開發中,頁面的排版、佈局很重要,使用者就是通過頁面操作來完成日常工作的。如果介面佈局不合理、操作不方便,使用者也不會對系統有好的印象、甚至有可能影響一個專案的成敗。我自己的經驗是,在開發某個功能模組時,除了仔細屬性該模組的功能需求和業務需求外,還會在草稿紙上簡單的把該功能的佈局畫出來(如果美工已經制作有頁面模型外)。例如:
Sencha Touch的佈局類似Extjs中的佈局,常用的有:BoxLayout、HBoxLayout、VBoxLayout、FitLayout、CardLayout。
4.1 BoxLayout、HBoxLayout、VBoxLayout(箱子佈局)
BoxLayout是箱子佈局,該佈局類似於藥店裡放置中草藥的大櫃子裡一個個小箱子那樣,把元件放置在容器中(Container)中。BoxLayout是HBoxLayout和VBoxLayout這兩個佈局類的父類,一般很少直接使用。
u HBoxLayout是水平箱子佈局,即把元件橫排的放置在容器中。
程式碼清單:
var viewport = newExt.Panel({
fullscreen:true,
//width: 500,
//height:200,
margin: '0 0 0 0',
layout: {
type: 'hbox', //指定layout佈局方式為HBoxLayout
align: 'stretch' //佈局裡的‘小容器’拉伸,類似window桌面圖片那樣,拉伸到整個頁面大
},
items: [{
flex: 1, //所佔寬度的比率
//height: 200,
style: 'border:1pxred solid', //自定義樣式
margin: '0 20 0 0', //設定邊框距離
items: [{
xtype:'button',
text:'第一',
margin:6
}]
},{
flex: 2,
//height: 200,
style: 'border:1pxred solid',
margin: '0 20 0 0',
html: '<divstyle="border:1px red dashed;margin:6px;">第二個小箱子</div>'
},{
flex: 3,
//height: 200,
style: 'border:1pxred solid',
items: [{
xtype:'button',
text:'第三',
margin:6
}]
}]
});
有兩個屬性需要關注一下:
l align: 'stretch',該屬性是設定容器裡‘小容器’的對齊方式。
l flex屬性是設定‘小容器’的寬度比率,具體的計算方式請參看文件。
當然還有其他的屬性,例如:style、margin、padding,這些屬性主要是設定樣式的。
u VBoxLayout垂直箱子佈局,即把元件垂直的放置在容器中。
程式碼清單:
var viewport = newExt.Panel({
fullscreen: true,
//width: 500,
//height:200,
margin: '0 0 0 0',
layout: {
type: 'vbox', //指定layout佈局方式為VBoxLayout
align:'stretch' //佈局裡的‘小容器’拉伸
},
items: [{
flex: 1, //所佔寬度的比率
//height: 200,
style: 'border:1pxred solid',
margin: '0 0 10 0',
items: [{
xtype:'button',
text:'第一',
margin: 6
}]
},{
flex: 2,
//height: 200,
style: 'border:1pxred solid',
margin: '0 0 10 0',
html: '<divstyle="border:1px red dashed;margin:6px;">第二個小箱子</div>'
},{
flex: 3,
//height: 200,
style: 'border:1pxred solid',
items: [{
xtype:'button',
text:'第三',
margin:6
}]
}]
});
FitLayout是佈局的基礎類,對應面板佈局配置項的名稱為fit,使用fit佈局將使面板子元素自動充滿容器,如果在當前容器中存在多個子面板則只有一個會被顯示。
程式碼清單:
var viewport = newExt.Panel({
fullscreen: true,
//width: 500,
//height:200,
margin: '0 0 0 0',
layout: 'fit', //指定layout佈局方式為FitLayout
items: [{
style: 'border:1pxred solid',
html: '<div style="border:1pxred dashed;margin:6px;">第一個小箱子</div>'
},{
style: 'border:1pxblue solid',
html: '<div style="border:1pxred dashed;margin:6px;">第二個小箱子</div>'
}]
});
CardLayout在sencha touch中是最常用的佈局,模仿本地應用的頁面轉換效果主要通過它來體現出來。它是擴充套件自FitLayout佈局,對應面板佈局配置項的名稱為card。該佈局會包含多個子面板,但任何時候都只有一個子面板處於顯示狀態,這種佈局經常用來製作嚮導和標籤頁。
各個字面板之間切換的途徑是呼叫setActiveItem方法,該方法接收一個子面板物件或id、索引作為引數。
程式碼清單:
//工具欄-toolbar
var funBar = {
xtype: 'toolbar',
title: 'CardLayout例子',
dock: 'top', //工具欄放置的位置(必須的屬性):top-上,bottom-下,left-左,right-右
scroll: 'horizontal',
height: 30,
items: [{
xtype: 'button',
text: '桌面',
ui: 'back',
//iconMask:true,
//iconCls:'home',
style: btStyle,
handler: function(){
window.location = prefix + '/index.action';
}
},{
xtype: 'button',
text: '第一個子面板',
style: btStyle,
handler: function(){
changeItem('p1');
}
},{
xtype: 'button',
text: '第二個子面板',
style: btStyle,
handler: function(){
changeItem('p2');
}
}]
};
//主介面
var viewport = newExt.Panel({
fullscreen: true,
margin: '0 0 0 0',
layout: 'card', //指定layout佈局方式為CardLayout
activeItem: 0,
dockedItems: [funBar],
items: [{
id: 'p1',
style: 'border:1pxred solid',
html: '<divstyle="border:1px red dashed;margin:6px;">第一個小箱子</div>'
},{
id: 'p2',
style: 'border:1pxblue solid',
html: '<divstyle="border:1px red dashed;margin:6px;">第二個小箱子</div>'
}]
});
//切換子面板
var changeItem = function(id){
viewport.setActiveItem(id, 'slide');
};
};
使用者與系統的互動,絕大部分是通過表單來進行。Sencha Touch的表單與Extjs的表單類似,只是新增了一些html5的元素,例如:url輸入框、email輸入框、search輸入框、Number輸入框、slider、toggle等。
表單元素有以下這些,其中有很多都是大家所熟悉的,在此就不做多說明,主要是說明一些新的表單元素及其常用屬性,其他(包括元件的方法、事件等)的請大家參照api文件:
l Text文字輸入框
簡單的文字輸入框,xtype為textfield(注意與extjs的不同哦)。常用的屬性有:
id:元件的唯一id,id屬性是全部元件都有的。
name:元件的名稱,name屬性也是全部元件都有的。
label:元件顯示的標記(注意與extjs的不同哦)。
labelAlign:label放置的位置,可選值有:left、right、top、bottom。
placeHolder: 輸入框為空值時自動顯示的值,相當於extjs的emptyText屬性。
maxLength:輸入框可以輸入內容的最大長度。
autoCapitalize:是否開啟首字母大寫(預設為false):true-是,false-否。
useClearIcon:是否使用清除圖示:true-當輸入框值改變後,右邊會顯示清除的小圖示。
required:標識為必填,只是做一個標識,表單提交時不會做驗證。
l Password密碼輸入框
密碼輸入框,xtype型別為passwordfield。
l Select下拉框
下拉框元件,xtype型別為selectfield。主要的屬性:
displayField:下拉框顯示的欄位名
valueField:下拉框值的欄位名(該欄位所指向的值將會被傳遞到後臺)
options:下拉選項物件陣列,物件的成員名稱必須與displayField和valueField的相一致。需要注意的是當select元件設定了store屬性,則本屬性的值將被忽略。
store:提供給select元件下拉選項的store物件例項,通過該屬性可以實現級聯下拉選擇。
l DatePicker日期選擇
日期選擇元件,xtype型別為datepickerfield。主要的屬性:
picker:用來建立日期選擇器的配置物件或直接使用一個日期選擇器例項。例如:
picker: {
yearFrom: 1910, //設定開始年份
cancelButton: '取消', //設定取消按鈕上的文字
doneButton: '完成', //設定完成按鈕上的文字
slotOrder: ['year', 'month', 'day'] //設定日期選擇器上顯示年月日的順序
}
l Checkbox多選框
多選框元件,xtype型別為checkboxfield。
l Radio單選框
單選框元件,xtype型別為radiofield。
l Email電子郵件輸入框
郵件輸入框元件,xtype型別為emailfield,是文字輸入框元件的子類。該元件暫時沒有很特別的屬性。
l Url超連結輸入框
超連結輸入框元件,xtype型別為urlfield,是文字輸入框元件的子類。該元件暫時沒有很特別的屬性。
l Slider滑動選擇器
滑動選擇器元件,xtype型別為sliderfield,該元件可以讓使用者通過手指橫向滑動來選擇值。主要的屬性:
minValue:slider的最小值。
maxValue:slider的最大值。
increment:每次滑動的增加值,只能為正整數,預設值為1。
注意:該元件的值不會傳遞到後臺,需要手工呼叫該元件的getValue()方法獲取設定的值,並把這個值設定到一個hidden元件中,以傳遞給後臺程式。可以通過該元件的change事件來檢測值的變化情況。
l Toggle開關切換器
開關切換器元件,xtype型別為togglefield,該元件是slider元件的子類,它只設置了兩個值:0和1。
該元件和slider元件一樣,需要手工呼叫getValue()方法把值設定到一個hidden元件,才能傳遞給後臺程式。
l Number數字輸入框
陣列輸入框元件,xtype型別為numberfield,是文字輸入框元件的子類,但只能輸入數字(包括負號與小數點)。
l Spinner微調器
微調器元件,xtype型別為spinnerfield,是number元件的子類。主要的屬性:
minValue:spinner的最小值。
maxValue:spinner的最大值。
incrementValue:每次點選-/+按鈕時,增加的值。
cycle:迴圈設定項,該屬性為true時,如果值已經到達maxValue設定的值,下一次點選則設定為minValue的值。同樣,如果已經達到minValue設定的值,下一次點選則設定為maxValue的值。
l Textarea文字輸入域
文字輸入域元件,xtype型別為textareafield,負責多行文字的輸入。
l Search搜尋輸入框
搜尋輸入框元件,xtype型別為searchfield,是文字輸入框元件的子類。該元件暫時沒有很特別的屬性。
1) 常用屬性:
l baseParams:Object
傳送到後臺的可選引數(只有當standardSubmit屬性為false時,即標準提交方式時,不會把這個屬性的引數值傳遞到後臺程式),該屬性的型別為Object,例如:{‘entity.title’:’hello kitty’}。
l dockedItems:Object/Array
放置到formpanel的一個或一系列元件,這些依附元件可以放置在formpanel的上下左右的位置。其典型應用是在panel上放置toolbars或tabbars,該屬性的型別為一個物件或一個物件陣列。
l standardSubmit:Boolean
是否執行一個標準提交,預設為false(非標準提交),該屬性的型別為boolean型。如果需要上傳附件,則必須執行標準提交,即該屬性設定為true。
l waitTpl: Object
設定一個ajax提交進度的模板,例如:提交後彈出‘正在儲存資料,請稍等…’的提示。
l record:Ext.data.Model
該屬性為只讀屬性,載入到form中的model例項,該屬性的型別是Ext.data.Model。
2) 常用方法:
u getRecord(): Ext.data.Model
該方法返回當前載入到form中的model例項。
u getValues(Boolean enabled): Object
返回一個包含有全部表單元素及其值的物件,物件的屬性與表單元素的name屬性一致,對於具有相同name屬性的checkbox或radio元素,它的值為一個值陣列。引數enabled若為true則只返回哪些disabled屬性為false或undefined的元素值,false則返回全部。
u load(Ext.data.Model instance): Ext.form.FormPanel
把一個model例項中的資料載入到對應的form元素中(model例項中的name與form元素中name屬性一致)。該方法是loadRecord方法的快捷鍵。通過該方法,我們可方便的把資料設定到form元素中。
u loadRecord(Ext.data.Model instance) : Ext.form.FormPanel
把一個model例項中的資料載入到對應的form元素中(model例項中的name與form元素中name屬性一致)。
u removeAll([Boolean autoDestroy]): Array
該方法可以刪除form容器中的全部元件,例如:從新增頁面儲存後跳轉到修改頁面,這時需要呼叫該方法把新增頁面的表單及其元素全部刪除,否則會出現相同名字和id的表單元素。sencha touch的頁面跳轉(setActiveItem方法),是隱藏原來的頁面的元素,在該頁面的最後自動加上後頁的html元素。
u reset(): Ext.form.FormPanel
表單重設方法,把表單元素的值設定為表單元素的起始值。
u submit(Object options): Ext.data.Connection
表單提交方法,如果form的standardSubmit屬性為true,則執行標準提交,否則執行基於ajax方式把form資料提交到後臺。該方法的引數options除非另有說明,一般包含如下的屬性值:
url:String,表單提交的目標地址。
method:String,表單提交方式,一般有POST和GET。
params: String/Object,提交到後臺的額外引數(即除了表單元素外的引數),如果已設定baseParams屬性的話,預設是該屬性值。提交時將會呼叫Ext.urlEncode方法對params值進行編碼。
submitDisabled: Boolean,該屬性值為true則提交表單中的全部元素,否則只提交disabled為false的表單元素值。
success: Function,表單提交到後臺並獲得後臺程式響應時的回撥函式,該函式包含兩個引數:form(Ext.FormPanel物件)和result(伺服器返回的結果物件),通過該回調函式,我們可根據後臺返回的資料進行一定的邏輯處理。
failure: Function,表單提交失敗時回撥函式,該函式包含兩個引數:form(Ext.FormPanel物件)和result(伺服器返回的結果物件)。
scope: Object
回撥函式的變數訪問。
u updateRecord(Ext.data.Model instance, Boolean enabled):Ext.form.FormPanel
把表單元素中的資料更新到model例項中。
表單資料載入,可以通過load方法從一個已有的model例項中把資料設定到表單元素中,也可以通過ajax從後臺獲取資料,然後通過load方法載入資料到表單元素中。
1) 從model例項中載入
//定義一個model
Ext.regModel('PersonInfo', {
fields: [
{name:'entity.linkman',type:'string'},
{name:'entity.password', type:'string'},
{name:'entity.sex',type:'string'},
{name:'entity.introduce',type:'string'}
]
});
//建立model例項資料
var person = Ext.ModelMgr.create({
'entity.linkman': 'hellokitty',
'entity.password' : 'hellokitty',
'entity.sex': 'm',
'entity.introduce' : '人見人愛 車見車載'
}, 'PersonInfo');
//載入資料到form元素中
Ext.getCmp('frmInfo').load(person);
2) 通過Ajax從後臺獲取資料並載入到表單中
該方式只是多了通過ajax從後臺獲取資料的步驟,其他的都與方式一是一樣的,在此不多說了。
表單資料提交有兩種方式:標準提交和ajax資料提交。為了更好的增強使用者的操作體驗,我們一般是採取ajax提交方式,即使是附件上傳功能,也可以通過提交到一個隱藏iframe方式,模擬ajax提交。
表單資料的提交通常是通過form元件的submit方法提交。
程式碼清單:
//提交資料
submitForm: function(sendFlag){
//驗證資料
if(!this.validate()){
return;
}
var_scope = this;
vartipMask = '正在儲存便函,請稍等...';
//是否傳送標識
Ext.getCmp('issended').setValue(sendFlag);
if(sendFlag== '1'){
tipMask = '正在傳送便函,請稍等...';
}
//彈出正在儲存的提示
varcmpMask = Ext.getBody();
loadMask(cmpMask,iconPath, tipMask);
//設定按鈕失效
vararrButton = [Ext.getCmp('btnSave'), Ext.getCmp('btnSend')];
enableButton(arrButton,false);
var form= Ext.getCmp('frmInfo');
form.submit({
url: this.saveURL,
method: 'POST',
success: function(thisForm,action){
unLoadMask(cmpMask);
//實體ID
var buId =action.result;
varsaveTip = '成功儲存便函資訊!';
if(sendFlag== '1'){
saveTip = '成功傳送便函資訊!';
}
var sa =Ext.Msg.alert('', saveTip);
setTimeout(function(){
sa.hide();
enableButton(arrButton, true);
}, 1500);
//儲存附件
_scope.saveAttach(_scope, buId, sendFlag);
},
failure: function(thisForm,action){
unLoadMask(cmpMask);
enableButton(arrButton, true);
if(action.result){
Ext.Msg.alert('',action.result);
}else{
Ext.Msg.alert('', '提交失敗,表單資料不完整!');
}
}
});
}
若是需要上傳附件,則必須使用標準提交,且需要設定form的enctype屬性。該屬性的設定,一般是在formpanel的afterrender監聽器中設定:
{
xtype: 'form',
id: 'frmAttach',
margin: '0 0 0 0',
standardSubmit: true, //只有標準提交(即不通過ajax方式提交),才可以上傳附件
items: [{
xtype: 'hiddenfield',
id: 'attRefId',
name: 'entity.id'
},{
html: '<iframe id="ifrmUpload"name="ifrmUpload" style="display:none"></iframe>'
}, this.renderAttachInfo(this, null)],
listeners: {
afterrender: function(frm){
//設定form的屬性
Ext.getDom('frmAttach').enctype = 'multipart/form-data';
Ext.getDom('frmAttach').method = 'POST';
Ext.getDom('frmAttach').target = 'ifrmUpload';
}
}
};
根據Sencha Touch技術框架的特點,前臺展示的絕大部分資料都是通過ajax方式獲取,譬如列表資料的獲取、表單資料的獲取等等。列表資料的獲取,一般是通過store元件和list元件進行結合;表單資料的獲取通常使用Ext.request方式獲取。
列表資料的獲取程式碼清單:
//資料列表
renderListData: function(){
//定義變數和函式的作用範圍
var _scope = this;
var st = newExt.data.Store({
model: _scope.model, //store元件使用的Ext.data.Model
//sorters: 'crtdt',
autoLoad: true, //是否自動載入資料
proxy: {
type: 'ajax',
actionMethods: 'POST',
url:_scope.url, //資料獲取的url地址
extraParams:_scope.extraParams, //請求的額外引數
startParam:'start',
limitParam:'limit',
reader: {
type: 'json', //reader型別-預設jsonReader,
root: undefined,//reader root-預設undefined
}
},
listeners: {
beforeload: function(st,oper){
oper.start = _scope.start; //設定分頁起始記錄
oper.limit = _scope.limit; //設定每頁顯示記錄數
},
load: function(st,records, successful){
if(successful){
//獲取後臺返回的記錄總數屬性
_scope.totalNum =st.getProxy().getReader().rawData.total;
//分頁按鈕控制
_scope.controlPageButtons();
//回撥外部函式-返回結果給外部函式
if(_scope.callbackFn){
_scope.callbackFn({listId:_scope.listId,total:_scope.totalNum});
}
}
}
}
});
//建立並返回list元件
return newExt.List({
id: _scope.listId,
//multiSelect: true,
//simpleSelect: true,
scroll: 'vertical',
store:st, //store元件物件
emptyText: '<divstyle="margin:2px;">'+_scope.emptyText+'</div>',
loadingText: '正在獲取資料',
itemTpl: _scope.itemTpl, //列表顯示的模板
listeners: {
itemtap: function(lt, idx, item,e){
//點選列表記錄時執行的函式
if(_scope.itemTapFn){
var record =lt.getStore().getAt(idx);
_scope.itemTapFn({listId:_scope.listId,record:record}, _scope.fnScope);
}
}
}
});
}
通過Ext.request方式獲取資料的程式碼清單:
//獲取資料
fetchData: function(){
var _scope= this;
Ext.Ajax.request({
method: 'POST',
url: prefix + '/doc/letter/manager!fetchEditData.action',
params: {
'entity.id':_scope.entityId //傳遞給後臺的引數
},
success: function(response,opts){
varobjResp = Ext.decode(response.responseText);
if(objResp.success){
varobjData = Ext.decode(objResp.result);
//呼叫自定義的函式把資料設定到form中
_scope.loadDataToForm(_scope,objData);
}else{
Ext.Msg.alert(objResp.result);
}
},
failure: function(response,opts){
Ext.Msg.alert('很抱歉,由於網路原因獲取資料出錯!');
}
});
}
鑑於目前行動網路的網速以及手機裝置瀏覽器的處理能力,為了提高應用響應的速度與使用者的操作體驗,使用sencha touch開發移動應用時需要注意一些情況:
u 後臺的資料傳輸要儘量精簡,前臺js書寫需要儘量簡潔。
u 介面要儘量精簡以及少用圖片,要保證應用的流暢,畢竟行動網路的網速遠比不上寬頻。
u 應用入口儘量要分模組,因為sencha touch整個應用只有一個入口的話,需要引入大量的js檔案,這樣可能會導致第一個頁面的響應速度很慢(js檔案需要下載到瀏覽器)。
u 一些通用功能儘量元件化,提高元件的重用。