Extjs MVC开发模式详解

在JS的开发过程中,大规模的JS脚本难以组织和维护,这一直是困扰前端开发人员的头等问题。Extjs为了解决这种问题,在Extjs 4.x版本中引入了MVC开发模式,开始将一个JS(Extjs)应用程序分割成Model-View-Controller三层,为JS应用程序的如何组织代码指明了方向,同时使得大规模JS代码变得更加易于重用和维护;这就是Extjs MVC开发模式的初衷。

在官方给出的MVC例子中,我们可以看到一个简单的列表编辑功能,这篇文章就围绕这个功能进行详细的讲解,让我们一起来揭开Extjs MVC的神秘面纱!

本文的示例代码适用于Extjs 4.x和Extjs 5.x,在Extjs 4.2.1 和Extjs 5.0.1中亲测可用!

本文由齐飞(youring2@gmail.com)原创,并发布在http://www.qeefee.com/article/extjs-mvc-in-detail,转载请注明出处!推荐更多Extjs教程Extjs5教程

常规开发模式下的列表编辑功能实现

我们先来看一下这个例子,它的功能非常简单:在页面打开的时候加载一个列表,当双击列表中一行数据的时候打开编辑窗口,编辑完成之后点击保存按钮,然后更新列表。截图如下:

imageextjs-mvc-in-detail

在常规的开发模式下,要实现这个功能非常简单,代码如下:

Ext.onReady(function () {
    //1.定义Model
    Ext.define("MyApp.model.User", {
        extend: "Ext.data.Model",
        fields: [
            { name: 'name', type: 'string' },
            { name: 'age', type: 'int' },
            { name: 'phone', type: 'string' }
        ]
    });

    //2.创建store
    var store = Ext.create("Ext.data.Store", {
        model: "MyApp.model.User",
        data: [
            { name: "Tom", age: 5, phone: "123456" },
            { name: "Jerry", age: 3, phone: "654321" }
        ]
    });

    //3.创建grid
    var viewport = Ext.create("Ext.container.Viewport", {
        layout: "fit",
        items: {
            xtype: "grid",
            model: "MyApp.model.User",
            store: store,
            columns: [
                { text: '姓名', dataIndex: 'name' },
                { text: '年龄', dataIndex: 'age', xtype: 'numbercolumn', format: '0' },
                { text: '电话', dataIndex: 'phone' }
            ]
        }
    });

    //4.添加双击编辑
    var grid = viewport.down("grid");
    grid.on("itemdblclick", function (me, record, item, index, e, eopts) {
        //5.创建编辑表单
        var win = Ext.create("Ext.window.Window", {
            title: "编辑用户",
            width: 300,
            height: 200,
            layout: "fit",
            items: {
                xtype: "form",
                margin: 5,
                border: false,
                fieldDefaults: {
                    labelAlign: 'left',
                    labelWidth: 60
                },
                items: [
                    { xtype: "textfield", name: "name", fieldLabel: "姓名" },
                    { xtype: "numberfield", name: "age", fieldLabel: "年龄" },
                    { xtype: "textfield", name: "phone", fieldLabel: "电话" }
                ]
            },
            buttons: [
                {
                    text: "保存", handler: function () {
                        win.down("form").updateRecord();
                        record.commit();
                        win.close();
                    }
                }
            ]
        });
        win.down("form").loadRecord(record);
        win.show();
    });
});

在这段代码中,我们用到了Model、Store、Grid,以及编辑的Window和Form。代码中已经给出了简单的注释,这不是今天重点要介绍的。

Extjs MVC开发模式

假设你从来没有接触过Extjs MVC开发模式,但是你知道ASP.NET MVC、或者别的任何语言下的MVC开发模式,那么我们来试想一下Extjs下的MVC该是什么样子?

  1. JS是需要在html页面中运行的,所以它要有一个宿主页面
  2. 它要有Model、View和Controller三层,这是MVC的基础,如果缺少了这三层,那还叫什么MVC呢?
  3. 这个JS程序可能需要有一个入口,因为JS不像ASP.NET那样根据URL来分配Controller和Action

好了,我们暂时想到了这么多,那么在实际的Extjs MVC开发过程中是什么样子呢?我们来看一下目录结构:

第一步,创建入口页面

创建一个html页面,我们使用mvc.html页面,在这个页面的同一个目录,我们创建一个app的文件夹,在这个文件夹下面用来放置js代码。mvc.html就是我们的程序宿主页面。

image

 

第二步,创建目录结构

在app文件夹下面创建controller、model、store和view文件夹,从名称上就知道他们该放置什么代码了吧。然后创建Application.js作为我们程序的入口文件,并在mvc.html中引用Application.js文件。

image

第三步,创建model

在model文件夹下面,创建user.js文件:

image

这个文件将存放我们的model,我们可以直接把最上面定义model的代码赋值到这里面。

app/model/User.js 的代码如下:

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

第四步,创建store

虽然store不是mvc中必须的步骤,但是作为数据仓库,store起到了数据存取的作用,grid、form等展现的数据都是通过store来提供的,因此store在extjs mvc开发模式中是必不可少的。

image

app/store/user.js 的代码如下:

Ext.define("MyApp.store.User", {
    extend: "Ext.data.Store",
    model: "MyApp.model.User",
    data: [
        { name: "Tom", age: 5, phone: "123456" },
        { name: "Jerry", age: 3, phone: "654321" }
    ]
});

第五步,创建view

为了实现列表和编辑功能,我们需要两个视图,分别是list和edit,那么view的结构如下:

image

app/view/user/List.js 对应我们的grid的定义,只不过将创建grid的实例改成了创建grid的扩展。

app/view/user/List.js 代码如下:

Ext.define("MyApp.view.user.List", {
    extend: "Ext.grid.Panel",
    alias: 'widget.userlist',
    store: "User",
    initComponent: function () {
        this.columns = [
            { text: '姓名', dataIndex: 'name' },
            { text: '年龄', dataIndex: 'age', xtype: 'numbercolumn', format: '0' },
            { text: '电话', dataIndex: 'phone' }
        ];
        this.callParent(arguments);
    }
});

app/view/user/edit.js 对应我们的window的定义,但同样是通过扩展的形式来实现的。

app/view/user/edit.js 代码如下:

Ext.define("MyApp.view.user.Edit", {
    extend: "Ext.window.Window",
    alias: "widget.useredit",
    title: "编辑用户",
    width: 300,
    height: 200,
    layout: "fit",

    items: {
        xtype: "form",
        margin: 5,
        border: false,
        fieldDefaults: {
            labelAlign: 'left',
            labelWidth: 60
        },
        items: [
            { xtype: "textfield", name: "name", fieldLabel: "姓名" },
            { xtype: "numberfield", name: "age", fieldLabel: "年龄" },
            { xtype: "textfield", name: "phone", fieldLabel: "电话" }
        ]
    },
    buttons: [
        { text: "保存", action: "save" }
    ]
});

注意:对于view类的创建,我们需要定义alias,这是为了方便我们通过xtype来创建该组件的实例。(如果没有alias,我们将很难在viewport和controller中使用 —— 这是我爬过的坑!)

第六步,创建controller

controller作为连接model、store和view的桥梁,在mvc开发模式中起到了至关重要的作用。如果说model定义了数据模式、store提供了数据存取的方法、view用来展示数据,那么controller将用来控制具体的数据操作。

image

app/controller/user.js 的代码如下:

Ext.define('MyApp.controller.User', {
    extend: 'Ext.app.Controller',
    stores: ['User'],
    models: ['User'],
    views: ['Viewport', 'user.List', 'user.Edit'],
    init: function () {
        this.control({
            'userlist': {
                itemdblclick: this.editUser
            },
            'useredit button[action=save]': {
                click: this.saveUser
            }
        });
    },
    editUser: function (grid, record) {
        var win = Ext.widget("useredit"); 
        win.down("form").loadRecord(record);
        win.show();
    },
    saveUser: function (btn) {
        var win = btn.up("window"),
            form = win.down("form"),
            record = form.getRecord();
        form.updateRecord();
        record.commit();
        win.close();
    }
});

我们来详细的说一下controller的这段代码。在这段代码中:

  1. 将定义好的model、store、view作为配置项添加到controller中,controller会加载这些文件;
  2. 在init方法中为view添加响应事件(这里添加事件的方法是通过query方式获取控件并添加的,这也是为什么要为view添加alias的原因)
  3. editUser方法和saveUser方法则是具体的操作内容

有了这些步骤,我们就将model、store、view联系在一起了。然后,我们进入Application.js文件中,完善我们的入口页面。

第七步,完善Application.js文件

在很多时候,Application.js文件也被简单的命名为app.js,它们的作用是一样的,为应用程序提供一个入口。它可以很简单,我们的Application.js文件代码如下:

Ext.application({
    name: "MyApp",
    appFolder: 'app',
    controllers: ["User"],
    autoCreateViewport: true,
    launch: function () {
        // 页面加载完成之后执行

    }
});
  • name: 应用程序名称
  • appFolder: 应用程序代码的目录,用来进行动态加载代码的
  • controllers: 应用程序使用到的控制器
  • autoCreateViewport: 是否自动创建Viewport,默认为false,我们这里设置为true,当它被设置为true的时候,应用程序会自动创建Viewport,这个Viewport的定义在我们的app/view/viewport.js 中;如果为false的时候,我们需要在launch中手动创建相应的视图。

第八步,Viewport.js的定义

Viewport作为我们应用程序的视图面板,可以被单独的定义在一个Viewport.js文件中。它的定义也很简单,通常用来将一个或多个view作为它的子控件。

app/view/viewport.js 代码如下:

Ext.define("MyApp.view.Viewport", {
    extend: "Ext.container.Viewport",
    layout: "fit",
    items: {
        xtype:"userlist"
    }
});

完成这些步骤之后,我们可以运行mvc.html来查看效果。

总结

Extjs MVC开发模式为我们提供了一个完善的代码组织和维护的方向,它的出发点是好的,但是在实际的操作过程中,我们会发现这种模式过于繁琐,这可能是由于我们的示例太过于简单而造成的。

Extjs MVC的Model、Store、View、Controller各层的代码都是通过Ext.define来创建类的形式完成的,因此在使用Extjs MVC之前,我们需要对Extjs的类系统有一定的认识,包括如何使用Ext.define自定义类

对于View层的控件,我们需要为它们指定一个alias属性,方便通过xtype创建对象,并可以在Controller中方便的找到他,为它的子控件添加具体的操作。



原址:http://www.qeefee.com/article/extjs-mvc-in-detail


ExtJS MVC架构讲解

欢迎加入我的ExtJS交流群 – 透视ExtJS 群号 256700289 入群暗号 Zen

大规模客户端应用通常不好实现不好组织也不好维护,因为功能和人力的不断增加,这些应用的规模很快就会超出掌控能力,ExtJS 4 带来了一个新的应用架构,不但可以组织代码,还可以减少实现的内容

新的应用架构遵照一个类MVC的模式,模型(Models)和控制器(Controllers)首次被引入。业界有很多种MVC架构,基本大同小异,ExtJS 4的定义如下:

  • Model模型 是字段和它们的数据的集合,例如User模型带有usernamepassword字段,模型知道如何持久化自己的数据,并且可以和其他模型关联,模型跟ExtJS 3 中的Record类有点像(区别是,Record只是单纯的扁平结构,而Model可以nest),通常都用在Store中去展示grid和其他组件的数据
  • View视图 是组件的一种,专注于界面展示 – grid, tree, panel 都是view
  • Controllers控制器 一个安放所有使你的app正确工作的代码的位置,具体一点应该是所有动作,例如如何渲染view,如何初始化model,和app的其他逻辑

这篇教程中将创建一个简单的管理用户数据的例子,做完这个例子,你会学会如何用ExtJS 4的架构把简单的应用组织到一起。

应用架构是关于提供结构和一致性,是关于真实的类和框架代码的,遵守约定可以带来很多重要的好处:

  • 每个应用都是相同的工作方式,所以你只需要学习一次
  • 可以很容易的共享代码,因为所有应用工作模式都一样
  • 可以创建属于自己的混淆的版本用于发布

File Structure文件结构

ExtJS 4 应用都遵循一个统一的目录结构,每个应有都相同。详情可以参见ExtJS 4 入门,MVC中,所有类都放在app目录里面,这个目录可以有子目录,代表的是命名空间(一个子目录对应一个命名空间),使用不同的目录存放views,models,controllers,stores,当我们完成例子的时候,目录结构应该和下面截图一样:

在这个例子中所有文件都在'account_manager'目录中,ExtJS SDK必须的文件在目录ext-4.0中,因此,index.html应该如下:

<html>
<head>
    <title>Account Manager</title>

    <link rel="stylesheet" type="text/css" href="ext-4.0/resources/css/ext-all.css">

    <script type="text/javascript" src="ext-4.0/ext-debug.js"></script>

    <script type="text/javascript" src="app.js"></script>
</head>
<body></body>
</html>

Creating the application in app.js 在app.js中创建应用

每个ExtJS 4的应用都从一个Application类的实例开始,这个实例包含应用的全局配置(例如应用的名字),这个实例也负责维护对全部模型、视图、控制器的引用的维护,还有一个launch函数,会在所有加载项加载完成之后调用。

让我们创建一个简单的Account Manager应用管理用户帐户。首先需要选择一个全局命名空间,所有ExtJS4应用都需要有一个全局命名空间,以让所有应用中的类安放到其中,这个例子中我们使用AM(Account Manager)

Ext.application({
    //今天有人问我,demo运行出错,
    //他妹的,官方demo错了 官方demo写的是 requires: 'Ext.container.Viewport',
    //这里的requires需要是个数组,extjs源码没处理好只有一个requires的情况
    requires: ['Ext.container.Viewport'],  
    name: 'AM',

    appFolder: 'app',

    launch: function() {
        Ext.create('Ext.container.Viewport', {
            layout: 'fit',
            items: [
                {
                    xtype: 'panel',
                    title: 'Users',
                    html : 'List of users will go here'
                }
            ]
        });
    }
});

首先我们调用了Ext.application创建了一个应用实例,并设置了应用名称”AM”,这样做会自动创建一个全局变量”AM”,并自动注册命名空间”AM”到Ext.Loader,用类似的方式也设置了app作为appFolder。另外在launch函数中,创建了一个Viewport,只包含一个撑满浏览器窗口的Panel

Defining a Controller 定义一个控制器

控制器是应用的粘合剂,它们所作的事情就是监听事件并执行动作,继续我们的Account Manager应用,创建一个控制器。创建app/controller/Users.js这个文件,并添加如下代码:

Ext.define('AM.controller.Users', {
    extend: 'Ext.app.Controller',

    init: function() {
        console.log('Initialized Users! This happens before the Application launch function is called');
    }
});

接下来在app.js中添加对Users控制器的引用:

Ext.application({
    ...

    controllers: [
        'Users'
    ],

    ...
});

当我们通过index.html查看应用,Users控制器会被自动加载(因为在app.js的Application中增加了引用),并且Usersinit方法会在launch之前调用

init方法是个极好的地方,可以用来设置如何和view交互,通常都使用Controller的一个方法controlcontrol方法使得监听view的事件变的容易,更新一下控制器,让它告知我们panel何时渲染:

Ext.define('AM.controller.Users', {
    extend: 'Ext.app.Controller',

    init: function() {
        this.control({
            'viewport > panel': {
                render: this.onPanelRendered
            }
        });
    },

    onPanelRendered: function() {
        console.log('The panel was rendered');
    }
});

我们已经更新了init方法,使用this.controll给视图设置监听器。这个controll方法,使用最新的组件查询引擎(ComponentQuery)可以快速方便的找到页面上的组件。如果你对ComponentQuery不熟悉,可以查看ComponentQuery文档进行详细了解。简要一点,ComponentQuery可以允许我们使用一个类似css选择器的方式找到组件。

在例子的init方法中我们应用了'viewport > panel',可以解释为“查找Viewport直接后代中的所有Panel组件”,然后我们提供了一个对象匹配事件名称(这个例子中只用了render)来提供响应函数。全部的影响就是无论哪个组件符合我们的选择器,当它的render事件触发时,我们的onPanelRendered函数都会被调用。

当我们运行应用程序,可以看到如下图所示:

这不是最激动人心的应用,但是它展示给我们,开始一段有组织的代码是多么容易。让我们增加一点内容,加一个grid。

Defining a View 定义一个视图

直到现在,我们的应用只有很少代码,只有两个文件app.jsapp/controller/Users.js,现在我们想增加一个grid显示所有系统中的用户,是时候更好的组织一下逻辑并开始使用视图了。

视图也是组件,通常都是ExtJS现有组件的子类,现在准备创建用户表,先创建app/view/user/List.js,添加代码:

Ext.define('AM.view.user.List' ,{
    extend: 'Ext.grid.Panel',
    alias : 'widget.userlist',

    title : 'All Users',

    initComponent: function() {
        this.store = {
            fields: ['name', 'email'],
            data  : [
                {name: 'Ed',    email: 'ed@sencha.com'},
                {name: 'Tommy', email: 'tommy@sencha.com'}
            ]
        };

        this.columns = [
            {header: 'Name',  dataIndex: 'name',  flex: 1},
            {header: 'Email', dataIndex: 'email', flex: 1}
        ];

        this.callParent(arguments);
    }
});

我们的视图类就是一个普通的类,这个例子中我们扩展了Grid组件,并设置了别名,这样我们可以用xtype的方式调用这个组件,另外我们也添加了storecolumns的配置。

接下来我们需要添加这个视图到Users控制器。因为我们用'widget.'设置了别名,所以我们可以使用userlist作为xtype,就像我们使用之前使用的'panel'

Ext.define('AM.controller.Users', {
    extend: 'Ext.app.Controller',

    views: [
        'user.List'
    ],

    init: ...

    onPanelRendered: ...
});

接下来修改app.js让视图在viewport中渲染,需要修改launch方法

Ext.application({
    ...

    launch: function() {
        Ext.create('Ext.container.Viewport', {
            layout: 'fit',
            items: {
                xtype: 'userlist'
            }
        });
    }
});

唯一需要注意的是我们在views数组中指定了'user.List',这告诉应用去自动加载对应的文件,ExtJS4 的动态加载系统会根据规则从服务器自动拉取文件,例如user.List就是规则,把.替换成/就是文件存放路径。刷新一下页面:

Controlling the grid 对列表的控制

注意onPanelRendered方法依然被调用,因为我们的grid依然满足'viewport > panel'选择器,因为我们的视图继承自Grid,从而继承自Panel

现在我们需要收紧一下选择器,我们使用xtype作为选择器替换之前的'viewport > panel',监听双击事件,以便继续做编辑用户信息:

Ext.define('AM.controller.Users', {
    extend: 'Ext.app.Controller',

    views: [
        'user.List'
    ],

    init: function() {
        this.control({
            'userlist': {
                itemdblclick: this.editUser
            }
        });
    },

    editUser: function(grid, record) {
        console.log('Double clicked on ' + record.get('name'));
    }
});

注意我们更换了组件查询选择器为'userlist',监听的事件更改为'itemdblclick',响应函数设置为'editUser',现在只是简单的日志出双击行的name属性:

可以看到日志是正确的,但我们实际想做的是编辑用户信息,让我们现在做,创建一个新的视图app/view/user/Edit.js

Ext.define('AM.view.user.Edit', {
    extend: 'Ext.window.Window',
    alias : 'widget.useredit',

    title : 'Edit User',
    layout: 'fit',
    autoShow: true,

    initComponent: function() {
        this.items = [
            {
                xtype: 'form',
                items: [
                    {
                        xtype: 'textfield',
                        name : 'name',
                        fieldLabel: 'Name'
                    },
                    {
                        xtype: 'textfield',
                        name : 'email',
                        fieldLabel: 'Email'
                    }
                ]
            }
        ];

        this.buttons = [
            {
                text: 'Save',
                action: 'save'
            },
            {
                text: 'Cancel',
                scope: this,
                handler: this.close
            }
        ];

        this.callParent(arguments);
    }
});

这回我们还是继承自一个现存的类Ext.window.Window,还是使用的initComponent方法去指定复杂的itemsbuttons对象,我们使用了一个'fit'布局和一个表单,表单包括了要编辑的用户信息字段,最后我们创建了两个按钮,一个用来关闭窗口,另一个用来保存变更。

现在我们要做的就是在控制器加载这个视图,渲染并且加载用户信息:

Ext.define('AM.controller.Users', {
    extend: 'Ext.app.Controller',

    views: [
        'user.List',
        'user.Edit'
    ],

    init: ...

    editUser: function(grid, record) {
        var view = Ext.widget('useredit');

        view.down('form').loadRecord(record);
    }
});

首先我们用Ext.widget方法创建了视图,这个方法等同于Ext.create('widget.useredit'),然后我们又一次借助组件查询找到了窗口中的表单,每个ExtJS4中的组件都有一个down方法,可以借助组件查询支持的选择器来迅速找到任意下层的组件。

双击表格中的一行可以看到:

Creating a Model and a Store

现在我们有了表单,可以开始编辑和保存用户信息了,但是这之前需要做一点点重构。

AM.view.user.List创建了一个内联的Store,这样可以工作但是我们需要把Store分离出来以便我们在应用的其他位置可以引用并更新其中的信息,我们把它放在它应该在的文件中app/store/Users.js

Ext.define('AM.store.Users', {
    extend: 'Ext.data.Store',
    fields: ['name', 'email'],
    data: [
        {name: 'Ed',    email: 'ed@sencha.com'},
        {name: 'Tommy', email: 'tommy@sencha.com'}
    ]
});

现在我们需要做两处变更,首先我们需要让Users初始化的时候加载这个Store

Ext.define('AM.controller.Users', {
    extend: 'Ext.app.Controller',
    stores: [
        'Users'
    ],
    ...
});

然后我们要把之前直接在视图中内联的store更改掉,app/view/user/List.js,改成用id引用store

Ext.define('AM.view.user.List' ,{
    extend: 'Ext.grid.Panel',
    alias : 'widget.userlist',

    //we no longer define the Users store in the `initComponent` method
    store: 'Users',

    ...
});

控制器的代码中中引入了store,store会被自动加载到页面并赋予一个storeId,这让视图中使用store变的容易(这个例子中,只要配置store: 'Users'就可以了)

现在我们只是在store中内联的定义了两个字段 (‘name’ 和 ‘email’),这样可以工作,但是ExtJS4中有一个强大的Ext.data.Model类,在编辑用户的时候我们可以借助它,使用Model重构一下Store,在app/model/User.js中创建一个Model:

Ext.define('AM.model.User', {
    extend: 'Ext.data.Model',
    fields: ['name', 'email']
});

这就是定义我们的Model需要做的,现在需要让Store引用Model替换掉使用内联字段的方式,并且让控制器也引用Model:

//the Users controller will make sure that the User model is included on the page and available to our app
Ext.define('AM.controller.Users', {
    extend: 'Ext.app.Controller',
    stores: ['Users'],
    models: ['User'],
    ...
});

// we now reference the Model instead of defining fields inline
Ext.define('AM.store.Users', {
    extend: 'Ext.data.Store',
    model: 'AM.model.User',

    data: [
        {name: 'Ed',    email: 'ed@sencha.com'},
        {name: 'Tommy', email: 'tommy@sencha.com'}
    ]
});

我们的重构可以让接下来的工作简单一下,但是不会影响现有功能,我们刷新一下页面,检查一下是否正常工作:

Saving data with the Model 利用模型保存数据

现在我们有了一个用户数据表,双击每一行都能打开一个编辑窗口,现在要做的是保存编辑变更,编辑窗口有一个编辑表单,还有保存按钮,现在我们更新一下控制器让保存按钮有响应:

Ext.define('AM.controller.Users', {
    init: function() {
        this.control({
            'viewport > userlist': {
                itemdblclick: this.editUser
            },
            'useredit button[action=save]': {
                click: this.updateUser
            }
        });
    },

    updateUser: function(button) {
        console.log('clicked the Save button');
    }
});

我们在this.control方法中增加了一个组件查询选择器'useredit button[action=save]',这里说明一下,这个选择器和第一个工作方式相同,注意我们定义保存按钮的时候增加了一个配置{action: 'save'},这个选择器的意思就是选择xytpe是useredit的组件下的所有action属性是save的按钮

检查一下updateUser是不是被调用了:

上图说明工作正常,接下来填充updateUser真正的逻辑。我们需要把数据从表单中取出,再设置回store中:

updateUser: function(button) {
    var win    = button.up('window'),
        form   = win.down('form'),
        record = form.getRecord(),
        values = form.getValues();

    record.set(values);
    win.close();
}

让我们分解一下这里都做了什么。我们的响应函数接收到按钮的引用,但是我们关心的是表单和窗口,通过按钮和组件查询,可以找到关心的东西,这里首先用了button.up('window')找到了窗口,然后用win.down('form')找到了表单。

这之后我们取出表单关联的record并用表单中的输入值更新了record,最后关闭了窗口关注回到表格上,我们把用户名更改为'Ed Spencer'点击保存应该可以看到:

Saving to the server 保存到服务器

很简单吧。让我们增加和服务器端的交互完成这个例子。现在我们还是应编码了两行表格的数据,现在让我们通过ajax加载:

Ext.define('AM.store.Users', {
    extend: 'Ext.data.Store',
    model: 'AM.model.User',
    autoLoad: true,

    proxy: {
        type: 'ajax',
        url: 'data/users.json',
        reader: {
            type: 'json',
            root: 'users',
            successProperty: 'success'
        }
    }
});

这里我们去除了'data'属性,替换成proxy,代理是让Store或者Model加载和保存数据的一个方式,有AJAX,JSONP,HTML5的localStorage本地存储等。这里我们使用了一个简单的AJAX代理,让它通过URL'data/users.json'加载数据。

我们同时给代理附加了一个reader,reader是用来把服务器返回的数据解码成Store能理解的格式,这次我们使用了JSON reader,并且指定了root和successProperty配置(JSON reader的详细配置看文档),最后我们创建一下数据文件data/users.json,输入内容:

{
    success: true,
    users: [
        {id: 1, name: 'Ed',    email: 'ed@sencha.com'},
        {id: 2, name: 'Tommy', email: 'tommy@sencha.com'}
    ]
}

其他的变更就是我们给Store设置了autoLoad属性并设置为true,这意味着Store生成之后会自动让Proxy加载数据,刷新一下页面应该是看到和之前同样的结果,不同的是现在不是在程序中应编码数据了

最后的事情是将变更传回服务器端,这个例子中我们使用静态的JSON文件,没有使用数据库,但足够说明我们例子的了,首先做一点点变化告知proxy用于更新的url:

proxy: {
    type: 'ajax',
    api: {
        read: 'data/users.json',
        update: 'data/updateUsers.json'
    },
    reader: {
        type: 'json',
        root: 'users',
        successProperty: 'success'
    }
}

依然从users.json读取数据,但是变更会发送到updateUsers.json,这里我们做一个模拟的应答回包以让我们知道程序可以正确工作,updateUsers.json只需要包含{"success": true},其他要做的就是让Store在编辑之后进行同步,需要在updateUser函数中增加一行代码:

updateUser: function(button) {
    var win    = button.up('window'),
        form   = win.down('form'),
        record = form.getRecord(),
        values = form.getValues();

    record.set(values);
    win.close();
    this.getUsersStore().sync();
}

现在我们可以运行一下整个例子,检查是不是每个功能都正常,编辑表格中的一行,看看能不能正确的把请求发送给updateUser.json

Deployment 发布

新出台的Sencha SDK Tools 点此下载 让ExtJS4的应用发布变的轻松。这个工具可以让你生成依赖清单,并生成一个最小化版本

详细介绍可以查看 ExtJS 入门

Next Steps 下一步

这里我们创建了一个非常简单的例子,但是基本功能都囊括了,你可以开始举一反三开发其他功能了,记得遵守开发模式,代码组织方式,以上代码的例子在Ext JS 4 SDK中,examples/app/simple目录中


  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值