1. 程式人生 > >[Ext JS6]應用程式框架介紹

[Ext JS6]應用程式框架介紹

Ext JS 對MVC 和MVVM兩種架構都支援。這兩種架構都是根據邏輯劃分程式的程式碼,兩種各有優劣。

MVC是什麼?

Model, View , Control的首字母。 在MVC架構中,大多數類都是模型,檢視和控制器。 使用者與檢視互動,檢視顯示模型中儲存的資料。 這些互動由Controller監控,然後根據需要通過更新View和Model來響應互動。 檢視和模型不直接交換, 由控制器負責更新。 也就是說, 在MVC模型中, 控制器包含基本所有的應用程式邏輯, 檢視基本不包含業務邏輯, 模型主要是資料介面,包含管理所述資料更改的業務邏輯。 MVC的目標是明確定義應用程式中每個類的職責。 因為每個類都有明確的責任,鬆耦合。 這使得應用程式更易於測試和維護,並且其程式碼更易於重用。

MVVM是什麼?

與MVC最大的區別是View 變成了ViewModel. ViewModel使用稱為“資料繫結”的技術協調Model的資料和View的資料表示之間的變化。

結果是模型和框架執行儘可能多的工作,最小化或消除直接操作View的應用程式邏輯。

對於開發者的變化

Ext JS5引進了MVVM框架, 並且之後建議使用這種方式開發。但是Ext JS4中的MVC架構會維持不變。

MVC 與MVVM選擇

如何選擇哪一個,首先看一下各個字母簡寫代表的意義: * (M) Model , 用於應用程式的資料。一組類(稱作Models)定義了資料的欄位。還可以與其他Model關聯。 Models 一般與Store結合給Gird或是其他元件提供資料。也可以用於任何資料邏輯的地方,類似驗證,轉換等。 * (V)View - 一種型別的元件, 類似grids, trees 和panels等 * (C)Controller -維護檢視的業務邏輯, 是程式可以執行。 * (VM)ViewModel - 是一個管理指定到某個View的資料的類。但資料發生變化時,相應的繫結的元件同步更新。

如何選擇: * 保持應用程式的風格一致, 如果已經有了,用就可以了 * 易於在不同應用程式之間共享程式碼 * 可以使用Sencha Cmd建立優化的正式環境版本。

建立一個例項的程式

使用Sencha Cmd的方式建立, 首先需要下載Sencha Cmd和Ext JS SDK, 接著,執行: ~ sencha -sdk local/path/to/ExtJS generate app MyApp MyApp cd app sencha app watch ~

應用程式概覽

檔案結構

app目錄: 所有的Store, Model, ViewModel, and ViewController類。 下面在細分子目錄: app/model app/store app/view : 包括ViewModel和Controllers, 最好是根據模組拆分子目錄, 類似以下的main子目錄。 這裡寫圖片描述

名稱空間

名稱空間的格式: <AppName>.<foldername>.<ClassAndFileName> 舉例: AppName: MyApp 目錄名: view/main 類檔名: Main.js

應用程式

看一下程式的入口檔案 index.html ~~~

<title>MyApp</title>


<script type="text/javascript">
    var Ext = Ext || {}; // Ext namespace won't be defined yet...

    // This function is called by the Microloader after it has performed basic
    // device detection. The results are provided in the "tags" object. You can
    // use these tags here or even add custom tags. These can be used by platform
    // filters in your manifest or by platformConfig expressions in your app.
    //
    Ext.beforeLoad = function (tags) {
        var s = location.search,  // the query string (ex "?foo=1&bar")
            profile;

        // For testing look for "?classic" or "?modern" in the URL to override
        // device detection default.
        //
        if (s.match(/\bclassic\b/)) {
            profile = 'classic';
        }
        else if (s.match(/\bmodern\b/)) {
            profile = 'modern';
        }
        else {
            profile = tags.desktop ? 'classic' : 'modern';
            //profile = tags.phone ? 'modern' : 'classic';
        }

        Ext.manifest = profile; // this name must match a build profile name

        // This function is called once the manifest is available but before
        // any data is pulled from it.
        //
        //return function (manifest) {
            // peek at / modify the manifest object
        //};
    };
</script>


<!-- The line below must be kept intact for Sencha Cmd to build your application -->
<script id="microloader" type="text/javascript" src="bootstrap.js"></script>

~~~

Ext JS使用Microloader 載入描述在 app.json檔案的資源。這樣的話, 就可以不把那些內容放入index.html中了。使用app.json, 所有應用程式的元資料都存在同一個位置,Sencha cmd可以以簡單有效的方式編譯應用程式。 app.json有很多註釋,提供了可以接受的配置的資訊的很好的資源。 關於beforeLoad 和平臺構建的更多資訊可以參考:[Developing for Multiple Environments and Screens guide.]

##### app.js 在之前使用cmd建立應用程式時, 建立了一個類(Application.js), 在 app.js 啟動了一個例項: ~~~ Ext.application({ name: ‘MyApp’,

extend: 'MyApp.Application',

requires: [
    'MyApp.view.main.Main'
],

// The name of the initial view to create. With the classic toolkit this class
// will gain a "viewport" plugin if it does not extend Ext.Viewport. With the
// modern toolkit, the main view will be added to the Viewport.
//
mainView: 'MyApp.view.main.Main'

//-------------------------------------------------------------------------
// Most customizations should be made to MyApp.Application. If you need to
// customize this file, doing so below this section reduces the likelihood
// of merge conflicts when upgrading to new versions of Sencha Cmd.
//-------------------------------------------------------------------------

}); ~~~

通過為mainView指定容器類,您可以將任何類用作Viewport。 在上面的示例中,我們已將MyApp.view.main.Main(一個TabPanel類)確定為我們的視口。

##### Application.js 每個Ext JS應用程式都以Application Class的例項開始。 此類旨在由app.js啟動,並且可以例項化以進行測試。 Application.js 內容由cmd自動產生。

Application Class包含應用程式的全域性設定,例如應用程式的名稱空間,共享儲存等。當應用程式過期時(瀏覽器快取版本與伺服器上的最新版本),將呼叫onAppUpdate方法。 提示使用者重新載入應用程式以便使用當前構建進行操作。

##### 檢視-Views 檢視就是一個元件,是Ext.Component的一個子類。檢視是應用程式用來進行視覺化顯示的部分。 看一下classic下面的Main.js 位置在:classic/src/view/main/Main.js ~~~ Ext.define(‘MyApp.view.main.Main’, { extend: ‘Ext.tab.Panel’, xtype: ‘app-main’,

requires: [
    'Ext.plugin.Viewport',
    'Ext.window.MessageBox',

    'MyApp.view.main.MainController',
    'MyApp.view.main.MainModel',
    'MyApp.view.main.List'
],

controller: 'main',
viewModel: 'main',

ui: 'navigation',

tabBarHeaderPosition: 1,
titleRotation: 0,
tabRotation: 0,

header: {
    layout: {
        align: 'stretchmax'
    },
    title: {
        bind: {
            text: '{name}'
        },
        flex: 0
    },
    iconCls: 'fa-th-list'
},

tabBar: {
    flex: 1,
    layout: {
        align: 'stretch',
        overflowHandler: 'none'
    }
},

responsiveConfig: {
    tall: {
        headerPosition: 'top'
    },
    wide: {
        headerPosition: 'left'
    }
},

defaults: {
    bodyPadding: 20,
    tabConfig: {
        plugins: 'responsive',
        responsiveConfig: {
            wide: {
                iconAlign: 'left',
                textAlign: 'left'
            },
            tall: {
                iconAlign: 'top',
                textAlign: 'center',
                width: 120
            }
        }
    }
},

items: [{
    title: 'Home',
    iconCls: 'fa-home',
    // The following grid shares a store with the classic version's grid as well!
    items: [{
        xtype: 'mainlist'
    }]
}, {
    title: 'Users',
    iconCls: 'fa-user',
    bind: {
        html: '{loremIpsum}'
    }
}, {
    title: 'Groups',
    iconCls: 'fa-users',
    bind: {
        html: '{loremIpsum}'
    }
}, {
    title: 'Settings',
    iconCls: 'fa-cog',
    bind: {
        html: '{loremIpsum}'
    }
}]

}); ~~~

檢視不包含任何應用程式邏輯,所以的檢視的邏輯部分需要包含在 ViewController裡面。 controller 和viewModel的配置都和View相關。 看一下”List”檢視的配置,listeners中 select的配置: ~~~

/** * This view is an example list of people. */ Ext.define(‘MyApp.view.main.List’, { extend: ‘Ext.grid.Panel’, xtype: ‘mainlist’,

requires: [
    'MyApp.store.Personnel'
],

title: 'Personnel',

store: {
    type: 'personnel'
},

columns: [
    { text: 'Name',  dataIndex: 'name' },
    { text: 'Email', dataIndex: 'email', flex: 1 },
    { text: 'Phone', dataIndex: 'phone', flex: 1 }
],

listeners: {
    select: 'onItemSelected'
}

});

~~~

##### Controller 配置 控制器配置允許您為檢視指定ViewController。 當以這種方式在檢視上指定ViewController時,它將成為事件處理程式和引用的容器。 這為ViewController提供了與檢視中觸發的元件和事件的一對一關係。

##### ViewModel 配置 viewModel配置允許您為檢視指定ViewModel。 ViewModel是此元件及其子檢視的資料提供者。 ViewModel中包含的資料通常通過將繫結配置新增到要呈現或編輯此資料的元件來使用。 在 “Main”檢視的例子中,title的配置是 bind {text:’{name}’}, 這是有ViewModel來管理的, 如果ViewModel的資料發生變化, title也會自動更新。

##### 控制器-Controllers 看一下自動產生的MainController.js ~~~

Ext.define(‘MyApp.view.main.MainController’, { extend: ‘Ext.app.ViewController’,

alias: 'controller.main',

onItemSelected: function (sender, record) {
    Ext.Msg.confirm('Confirm', 'Are you sure?', 'onConfirm', this);
},

onConfirm: function (choice) {
    if (choice === 'yes') {
        //
    }
}

}); ~~~

回頭看看List檢視 List.js, 可以注意到為Grid選擇事件的設計的功能。 該處理程式對映到父檢視Main.js,controller中名為onItemSelected的函式。 如您所見,此控制器已準備好處理該事件而無需特殊設定。 這使得為應用程式新增邏輯非常容易。 因為控制器與其檢視具有一對一的關係,需要做的就是定義onItemSelected函式。

ViewControllers的作用:

-讓使用”listeners”和”reference”配置的方式連線檢視更顯而易見 -利用檢視的生命週期自動管理其關聯的ViewController。 從例項化到銷燬,Ext.app.ViewController繫結到引用它的元件。 同一檢視類的第二個例項將獲得自己的ViewController例項。 當銷燬這些檢視時,它們的相關ViewController例項也將被銷燬。 -提供封裝以使巢狀檢視直觀。

##### ViewModels 看一下 MainModel.js,位置在app/view/main/MainModel.js ~~~ Ext.define(‘MyApp.view.main.MainModel’, { extend: ‘Ext.app.ViewModel’,

alias: 'viewmodel.main',

data: {
    name: 'MyApp',

    loremIpsum: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'
}

//TODO - add data, formulas and/or methods to support your view

}); ~~~ ViewModel是一個管理資料物件的類。 然後,該類允許對此資料感興趣的檢視繫結到該資料並通知更改。 ViewModel與ViewController一樣,歸引用它的檢視所有。 由於ViewModel與檢視相關聯,因此它們還能夠連結到元件層次結構中的祖先元件所擁有的父ViewModel。 這允許子檢視簡單地“繼承”其父ViewModel的資料。

在檢視類中(Main.js)通過viewModel配置將View和ViewModel關聯起來。 此連結允許使用setter繫結配置,以宣告方式自動將viewModel中的資料設定到檢視上。 資料在“MainModel.js”示例中是內聯的。 也就是說,您的資料可以是任何東西,來自任何地方。 資料可以由任何型別的代理(AJAX,REST等)提供。

#### Models 和 Stores Models和Stores構成了應用程式的資訊門戶,大多數資料都是由這兩個類傳送,檢索,組織和“建模”的。

##### Models - 模型

Ext.data.Model 用來表示應用程式中任何型別的可持久資料。每個模型都有欄位和函式,允許您的應用程式“建模”資料。 Models最常與Stores一起使用。 然後,Stores可以被資料繫結元件(如Grid,Tree和Charts)使用。 舉例來說:

~ Ext.define('MyApp.model.User', { extend: 'Ext.data.Model', fields: [ {name: 'name', type: 'string'}, {name: 'age', type: 'int'} ] }) ~

檔案位置 app/model/