原文:Building Maintainable Controllers in Ext JS Apps

在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.

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

  1. 【翻译】在Ext JS应用程序中使用自定义图标

    原文:Using Custom Icons in Your Ext JS App 作者:Lee BoonstraLee is a technical trainer at Sencha. She's ...

  2. 【翻译】Ext JS 6.2 早期访问版本发布

    原文:Announcing Ext JS 6.2 Early Access 非常开心,Sencha Ext JS 6.2早期访问版本今天发布了.早期访问版本的主要目的是为了让大家进行测试并评估Ext ...

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

    早期访问版本是什么 如何参与 都包括什么 Sencha Ext JS 6 Sencha Pivot Grid Sencha Cmd 6 JetBrains IDE插件 反馈 原文:Announcing ...

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

    工具包ToolKits 发布 包的命名 Fashion 图表 ItemEdit插件 网格 电子表格 可操作模式Actionable Mode和可访问性 LazyItems插件 屏幕阅读器支持可访问性 ...

  5. 【翻译】Ext JS最新技巧——2016-3-4

    原文:Top Support Tips Kevin Cassidy:Grid水印 Ext JS的Grid是一个便于在布局中显示信息的伟大工具.有些用户可能会希望将这些信息打印为会议资料或宣传材料,而且 ...

  6. 【翻译】Ext JS最新技巧——2015-10-21

    原文:Top Support Tips Kevin Cassidy:全宽度的字段错误信息 有考虑过让验证信息显示在表单字段的下面(msgTarget:'under'),但最后发现验证信息被压缩显示了吗 ...

  7. 【翻译】Ext JS最新技巧——2015-8-11

    原文:Top Support Tips Seth Lemmons:使用棒极了的Awesome Font Ext JS 6附带了一个新的海卫一主题,可以使用Font Awesome字体作为背景图像的图标 ...

  8. 【翻译】Ext JS 6 Beta发布

    原文:Ext JS 6 Beta is Now Available 概述 Ext JS 6的好处 新的Ext JS功能和工具 需要你的反馈意见 概述 很高兴,Ext JS 6 beta版本现在发布了. ...

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

    原文:ExtJS - Efficient coding style guide 作者:Raja 切勿使用"new"关键字:在Ext JS中,使用"new"关键字 ...

随机推荐

  1. TortiseGit 添加SSH-Key

    TortoiseGit 使用扩展名为ppk的密钥,而不是ssh-keygen生成的rsa密钥.使用命令ssh-keygen -C "邮箱地址" -t rsa产生的密钥在Tortoi ...

  2. mysql常见的优化需要注意的点

    1.explain分析explian引用索引基数show indexes from table_name;主键索引具有最好的基数 测试时 不走缓存SELECT SQL_NO_CACHE id from ...

  3. aways on 配置部署(二)——配置域

    前一篇中我们基本了解了配置aways on的三个步骤,本篇就具体讲解如何配置域. DNS的配置 上篇可以看到三台服务器的ip地址,网关,DNS等配置,其中sqlDNS服务器的dns为自己的ip地址,s ...

  4. JAVA反射之Class类的练习

    package zhang; /** * JAVA反射之CLass类的练习 * * 在面向对象的语言里,万事万物皆对象,那么类是谁的对象呢? * 类的类型是CLass * * */ class Tes ...

  5. Spring boot 整合 Mybatis + Thymeleaf开发web(二)

    上一章我把整个后台的搭建和逻辑给写出来了,也贴的相应的代码,这章节就来看看怎么使用Thymeleaf模板引擎吧,Spring Boot默认推荐Thymeleaf模板,之前是用jsp来作为视图层的渲染, ...

  6. Node.js JXcore 打包

    Node.js 是一个开放源代码.跨平台的.用于服务器端和网络应用的运行环境. JXcore 是一个支持多线程的 Node.js 发行版本,基本不需要对你现有的代码做任何改动就可以直接线程安全地以多线 ...

  7. 全新 Kali Linux 系统安装指南

    Kali Linux 系统可以说是在安全测试方面最好的开箱即用的 Linux 发行版.Kali 下的很多工具软件都可以安装在大多数的 Linux 发行版中,Offensive Security 团队在 ...

  8. Android Multimedia框架总结(二十四)MediaMuxer实现手机屏幕录制成gif图

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/53866405 前言:上篇中,介绍 ...

  9. Spring Boot 中应用Spring data mongdb

    摘要 本文主要简单介绍下如何在Spring Boot 项目中使用Spring data mongdb.没有深入探究,仅供入门参考. 文末有代码链接 准备 安装mongodb 需要连接mongodb,所 ...

  10. ELK平台的搭建

    ELK是指Elasticsearch + Logstash + Kibaba三个组件的组合.本文讲解一个基于日志文件的ELK平台的搭建过程,有关ELK的原理以及更多其他信息,会在接下来的文章中继续研究 ...