【翻译】在Ext JS应用程序中构建可维护的控制器

原文:Building Maintainable Controllers in Ext JS Apps

  • 你好You Had Me
  • 你是Tearing Me Apart
  • 模板We Dont Need to be aware of No Stinkin的模板
  • What Weve Got Here是一个失败的沟通者
  • 聪明的视图是重点且易于维护和测试

在eMortgage Logic公司,2011年底开始使用Ext JS 4。当时,还不知道如何正确编写Ext JS应用程序,但最后还是掌握了如何让应用程序实现所需的方法。不过,这并不意味着能很好的去实现他们。最终结果是,应用程序是由十几个大规模控制器实现处理的,而同时,视图使用的是一组简单的配置。控制器掌控着一切,但随着时间的推移,控制器变得越来越难于维护,这就让人开始怀疑当初的代码是否妥当了。

最后,我们试图让视图变得聪明一点,沿着这个思路,我们有点开窍了。最终,终于知道如何在控制器和视图之间划清界线了。为了说明我们团队新发现的这个知识,我撰写了以下这个指南。该指南使用了一个简单的方式来说明如何拆卸大的控制器并替换他们的的逻辑代码,以便于维护。这不仅有利于短期内使用Ext JS 4的团队,也有利于近期升级到Ext JS 5视图控制器的团队。

在这篇文章,将创建一个小型的控制和有几个需求的简单视图,然后通过几个步骤来分离他们。

本文最终的目标是创建一个实现以下要求的控制器和视图:

  • 提供一个表单让用户输入喜好
  • 保持喜好到用户的记录
  • 更新用户的名字和喜好等信息

你好,“You Had Me”

查看相关代码

创建的视图将允许当前用户去查看和更新他们的爱好,该视图将使用build方法,因此后续工作会很简单。

app/view/Hobby.js

Ext.define(‘Example.view.Hobby‘, {
    extend: ‘Ext.form.Panel‘,
    alias: ‘widget.hobbyview‘,
    initComponent: function () {
        var me = this;

        me.items = me.buildItems();

        me.callParent(arguments);
    },
    buildItems: function () {
        return [
            {
                xtype: ‘textfield‘,
                name: ‘FavoriteHobby‘
            },
            {
                xtype: ‘button‘,
                itemId: ‘save‘,
                text: ‘Save‘
            },
            {
                xtype: ‘component‘,
                itemId: ‘hobbyTpl‘,
                tpl: ‘{Name}\‘s favorite hobby is {FavoriteHobby}‘
            }
        ];
    }
});

下面,将创建控制器来管理视图:

app/controller/Hobby.js

Ext.define(‘Example.controller.Hobby‘, {
    extend: ‘Ext.app.Controller‘,
    init: function () {
        this.control({
            ‘hobbyview button#save‘: {
                click: this.onSaveButtonClick
            }
        });
    },
    onSaveButtonClick: function (button) {
        var form = button.up(‘form‘),
            values = form.getValues(),
            user;

        // We will assume the application provides a way to get the currently logged-in user.
        user = this.getApplication().getCurrentUser();

        user.set(values);
        user.save();

        form.down(‘#hobbyTpl‘).update({
            Name: user.get(‘Name‘),
            FavoriteHobby: values.FavoriteHobby
        });
    }
});

尽管是一个非常简单的控制器,但它知道视图对它有意见。

控制器要知道:

视图有一个ItemId为save的按钮

按钮是表单的一个子组件

如何从视图的表单中获得值

表单有一个itemId为hobbyTpl的子组件,如何去更新它?

表单不知道用户这个概念

控制器的一切完全依赖于视图的保存按钮和视图自身的结构,这将导致控制器和视图必须紧密耦合,譬如,如果保存按钮在表单组件的之外,控制器就不得不重写。另外,如果itemId为hobbyTpl的组件被改变,控制器也需要进行相应的更改。视图中的任何微小变化都可能会令控制器出现问题。

你是Tearing Me Apart

查看相关代码

现在,你可以已经意识到控制器的一些问题了,下面就来解决这些问题。首先是要让视图与用户关联。

app/view/Hobby.js

Ext.define(‘Example.view.Hobby‘, {
    // ...

    bindUser: function (record) {
        this.userRecord = record;
    },
    getUser: function () {
        return this.userRecord;
    }
    // ...
});

通过设置一些方法来关联用户,这样就可以很容易的调整视图方法而不需要修改控制器。通过这些附加项,就可以通过传递一个实例或稍后调用bindUser方法后让视图关注用户记录。这样,还可以获取绑定的用户,而控制器则无须了解太多。

接下来,要让控制器允许视图去管理用户记录并更新数据。

app/controller/Hobby.js

Ext.define(‘Example.controller.Hobby‘, {
    // ...
    onSaveButtonClick: function (button) {
        var form = button.up(‘form‘),
            values = form.getValues(),
            user = form.getUser();

        user.set(values);
        user.save();

        form.down(‘#hobbyTpl‘).update({
            Name: user.get(‘Name‘),
            FavoriteHobby: values.FavoriteHobby
        });
    }
});

很不错了,不过清单里还有一件事没做,那就是控制器还是要了解视图的结构,现在要做的就是让它更灵活。

下面更新一下清单:

控制器知道

  • 视图有一个ItemId为save的按钮
  • 按钮是表单的一个子组件
  • 如何从视图的表单中获得值
  • 表单有一个itemId为hobbyTpl的子组件,如何去更新它?
  • 表单不知道用户这个概念

模板?We Don’t Need [to be aware of] No Stinkin的模板

查看相关代码

视图一直很想知道为什么控制器不能专注于自己的商业逻辑,而这可通过移除模板的相关内容来让它少管点闲事。

视图希望它的模板在保存按钮被单击时被更新,为了实现这个目标,需要添加事件处理。

app/view/Hobby.js

Ext.define(‘Example.view.Hobby‘, {
    // ...
    onSaveClick: function () {
        var me = this,
            values = me.getValues(),
            user = me.getUser();

        me.down(‘#hobbyTpl‘).update({
            Name: user.get(‘Name‘),
            FavoriteHobby: values.FavoriteHobby
        });
    },
    buildItems: function () {
        var me = this;

        return [
            {
                xtype: ‘textfield‘,
                name: ‘FavoriteHobby‘
            },
            {
                xtype: ‘button‘,
                itemId: ‘save‘,
                text: ‘Save‘,
                listeners: {
                    click: me.onSaveClick,
                    scope: me
                }
            },
            {
                xtype: ‘component‘,
                itemId: ‘hobbyTpl‘,
                tpl: ‘{Name}\‘s favorite hobby is {FavoriteHobby}‘
            }
        ];
    }
});

现在,视图将处理更多的视图事务,而控制器也可以更简单了。

app/controller/Hobby.js

Ext.define(‘Example.controller.Hobby‘, {
    // ...
    onSaveButtonClick: function (button) {
        var form = button.up(‘form‘),
            values = form.getValues(),
            user = form.getUser();

        user.set(values);
        user.save();
    }
});

不幸的是,控制器还是能看到不少的视图组件,不过至少列表中的事情又少了一件:

控制器知道

  • 视图有一个ItemId为save的按钮
  • 按钮是表单的一个子组件
  • 如何从视图的表单中获得值
  • 表单有一个itemId为hobbyTpl的子组件,如何去更新它?
  • 表单不知道用户这个概念

What We’ve Got Here是一个失败的沟通者

查看相关代码

现在一举解决余下的问题的时候了,这需要通过事件来实现视图与控制器之间的沟通。控制器只需要知道视图要获取数据,并且需要保存数据。

在onSaveClick事件中,视图中已经聚集了控制器所需的所有数据,因此这里只需要从这里出发一个事件。

app/view/Hobby.js

Ext.define(‘Example.view.Hobby‘, {
    // ...
    onSaveClick: function () {
        var me = this,
            values = me.getValues(),
            user = me.getUser();

        me.fireEvent(‘save‘, me, values, user);

        me.down(‘#hobbyTpl‘).update({
            Name: user.get(‘Name‘),
            FavoriteHobby: values.FavoriteHobby
        });
    },
    // ...
});

这小小的改变就可以让控制器变得足够简单,它只需要知道视图的存在,并会触发一个save事件。

app/controller/Hobby.js

Ext.define(‘Example.controller.Hobby‘, {
    extend: ‘Ext.app.Controller‘,
    init: function () {
        this.control({
            ‘hobbyview‘: {
                save: this.onSave
            }
        });
    },
    onSave: function (view, values, user) {
        user.set(values);
        user.save();
    }
});

现在,控制器终于不需要再了解视图的结构了。控制器只保存数据,而是他只显示数据。

只要视图一直保持触发save时间,现在就不需要大量修改控制器了。

控制器知道

  • 视图有一个ItemId为save的按钮
  • 按钮是表单的一个子组件
  • 如何从视图的表单中获得值
  • 表单有一个itemId为hobbyTpl的子组件,如何去更新它?
  • 表单不知道用户这个概念

聪明的视图是重点且易于维护和测试

了解如何拆卸猛犸级的控制器对于团队更好的管理类来说是相当有帮助的。不但是控制器,视图也变得更集中和易于维护,他们也易于测试,而这也更接近于Ext JS视图控制器的功能。让视图变得更聪明还便于应用程序重用他们。

要知道的是:

  • 视图完全有能力管理自己的数据
  • 控制器应该以不了解视图内部结构为前提
  • 自定义事件是处理视图于控制器之间通信的最完美方式

作者:John Krull

John is a Software Engineer at eMortgage Logic. He has experience in web app development, agile software dev, and UI/UX design. He sp*ecializes in Ext JS, JavaScript, PHP, Perl, MySQL, HTML, and CSS.

时间: 2024-11-08 20:43:39

【翻译】在Ext JS应用程序中构建可维护的控制器的相关文章

【翻译】Ext JS 6早期访问版本发布

早期访问版本是什么 如何参与 都包括什么 Sencha Ext JS 6 Sencha Pivot Grid Sencha Cmd 6 JetBrains IDE插件 反馈 原文:Announcing Ext JS 6 Early Access Release 在令人惊艳的SenchaCon 2015最后一周,我们非常兴奋,因为Ext JS 6早期访问版本要发布了.在Ext JS 6,可以使用单一的javascript框架来无缝的创建基于桌面.平板和智能手机的应用程序. 下载Ext JS 6早期

【翻译】Ext JS 5的平板支持

原文:Ext JS 5 Tablet Support Ext JS已被公认为桌面Web应用程序的领先框架.自从平板开始在全球挑战PC的销售,无论是个人还是企业,电脑横向的应用已经产生急剧的变化.Sencha意识到了这种变化,并推出了包含新功能和进行优化了的Ext JS 5. Ext JS从Sencha Touch 2学到了一些新把戏.多年最好的移动Web应用程序框架经验的沉淀要应对现代平板电脑上的桌面显示,那是卓卓有余的.通过类系统.事件管理.窗口小部件和新的部署选项就可以了解到这些更新. 除了

【翻译】Ext JS最新技巧——2014-5-12

原文:http://www.sencha.com/blog/top-support-tips-may-2014?mkt_tok=3RkMMJWWfF9wsRoluazJZKXonjHpfsX77OQlXK%2B%2FlMI%2F0ER3fOvrPUfGjI4AT8NjI%2BSLDwEYGJlv6SgFSbfBMbdlybgMWRA%3D Seth Lemmons:为网格行设置不同的高度 在整个网格中,行高通常都会保持为同一高度.然而,这并不适用于所有情形,有时候需要根据单元格中的数据来自动调整

【翻译】Ext JS 6有什么新东西?

工具包ToolKits 发布 包的命名 Fashion 图表 ItemEdit插件 网格 电子表格 可操作模式Actionable Mode和可访问性 LazyItems插件 屏幕阅读器支持可访问性 微加载Microloader Touch网格 原文:http://docs.sencha.com/extjs/6.0/whats_new/6.0.0/whats_new.html Ext JS在Sencha框架中引入了许多新的和令人兴奋的改进.这些变化为基于所有现代浏览器.设备和屏幕尺寸带来了新的功

【翻译】Ext JS——高效的编码风格指南

原文:ExtJS - Efficient coding style guide 作者:Raja 切勿使用"new"关键字:在Ext JS中,使用"new"关键字来创建一个组件或类的实例是一种错误的做法,因为这没有遵循组件的生命周期.应该使用Ext.create方法来创建对象,例如: 错误: var obj = new Ext.panel.Panel(); 正确: var obj = Ext.create('Ext.panel.Panel'); 初始化直接量:不要直接

【翻译】在Sencha应用程序中使用插件和混入

原文:Using Plugins and Mixins in Your Sencha Apps 概述 当扩展一个框架类的功能的时候,通常都会直接将新功能写入派生类,然而,如果所需的同一功能存在于多个组件,那最有效的方式就是将它定义为一个插件或混入.插件和混入都是用来将额外功能添加到其他类的类.在本文,将介绍这些类是什么,他们之间的区别,以及他们如何工作.在Sencha Fiddle,我们准备了一些示例来演示这些概念. 插件是什么且如何使用它? 插件是一个类,用来为 Ext.Component(或

【翻译】Ext JS最新技巧——2014-10-30

原文:Top Support Tips Greg Barry:Ext JS 5的ExtraParams Ext JS 4允许用户直接将extraParams添加到一个链接,类似如下代码: Ext.Ajax.extraParams = { foo: "bar" }; 由于Ext JS5对数据包进行了修改,该方法就不再可行了.现在,需要使用 setExtraParams和getExtraParams方法来为Ext.data.Connection提供参数,例如: Ext.Ajax.setEx

【翻译】在Ext JS 5应用程序中如何使用路由

原文:How to Use Routing in Your Ext JS 5 Apps 简介 Ext JS 5是一个重要的发布版本,它提供了许多新特性来创建丰富的.企业级的Web应用程序.MVVM和双向数据绑定为开发人员承担了大量的繁重工作.在Ext JS 5种,另一个新特性就是路由,它可以在控制器内轻松的管理历史记录.前进和后退按钮是每个浏览器都会拥有的公共用户接口,现在,使用Ext JS 5在单页面应用程序中处理导航变得相当简单了. Ext JS 5路由 在Ext JS,已经可以使用Ext.

在Ext JS 5应用程序中如何使用路由

简介 Ext JS 5是一个重要的发布版本,它提供了许多新特性来创建丰富的.企业级的Web应用程序.MVVM和双向数据绑定为开发人员承担了大量的繁重工作.在Ext JS 5种,另一个新特性就是路由,它可以在控制器内轻松的管理历史记录.前进和后退按钮是每个浏览器都会拥有的公共用户接口,现在,使用Ext JS 5在单页面应用程序中处理导航变得相当简单了. Ext JS 5路由 在Ext JS,已经可以使用Ext.util.Histroy类来处理历史记录的变化,但在Ext JS 5,这个处理变得更容易