[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/

猜你喜欢

转载自blog.csdn.net/oscar999/article/details/82731817