1. 程式人生 > >移動Web應用開發技術講解-Sencha Touch 1.1

移動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。下面簡單介紹一下這三個開發框架。

Sencha Touch:Sencha Touch框架是世界上第一個基於HTML 5的Mobile App框架,它可以讓Web App看起來像Native App。美麗的使用者介面元件和豐富的資料管理,全部基於最新的HTML 5和CSS3的 WEB標準,全面相容Android和iOS裝置。SenchaTouch相對來說是一個重量級的移動Web應用框架,適合用於開發業務邏輯比較複雜的移動Web應用。優點:針對觸控式螢幕豐富的UI設計支援複雜互動、純JavaScript搞定佈局、版本穩定效能尚可。

JQuery Mobile:JQuery Mobile 是 jQuery 在手機上和平板裝置上的版本,不僅給主流移動平臺帶來jQuery核心庫,而且釋出一個完整統一的jQuery移動UI框架,支援全球主流的移動平臺,它屬於一個輕量級的移動Web應用框架,可以非常便捷的開發出基於Html5的移動網站。優點:超多平臺支援、入門簡單傳統div佈局;缺點:UI支援比較簡單不適合複雜互動。

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   一些通用功能儘量元件化,提高元件的重用。