在《Ext JS 6.2实战》一书中,定义了用于实现应用程序本地化的I18N类,而在定义表单字段时,是直接使用I18N来引用表单字段的标签文本的,当表单字段比较多,项目的表单也比较多的时候,老是这样引用,也挺麻烦的,因而,最好的方式是让字段自己根据name配置项定义的名称去I18N取标签文本。本文要做的就是要实现这个。

要实现自动获取标签文本,需要解决的问题主要是以下两个:
- 怎么修改才能涵盖所有的字段,不需要修改每一个字段的定义
- 如何获取标签文本

第一个问题好解决,因为表单字段有一个基类Ext.form.field.Base,从这个类入手就行了。

第二问题需要解决的就是如何根据name去获取标签文本。在I18N的定义中,对于表单字段的定义的标签文本定义,都添加了一个“xxxxModel”的名称来管理标签文本,以避免出现名称相同而标签文本表示不同的问题。要让字段自动获取到标签文本,就必须让字段知道这个“xxxxModel”的名称。要实现这个,挺简单的,为字段添加一个配置项来指定这个名称就好了。

基本思路清晰后,就可以动手来实现了。首先要做的是在《Ext JS 6:Visual Studio Code、创建包和权限管理 》一文中实现的公共包中,在overrides文件夹添加文件夹form\field,并添加一个名为Base.js的脚本文件。脚本添加后,加入以下代码:

Ext.define('Common.overrides.form.field.Base', {
    override: 'Ext.form.field.Base',

    entityName: null,
});

代码中,entityName就是新增的用来获取标签文本的实体名称。

为了能在字段初始化前完成标签文本的设置,我们需要重写Base字段的initComponent方法。把Ext.form.field.Base的initComponent方法复制到类中,然后在callParent方法前添加以下代码:

var me = this,
            entity= me.entityName,
            name = me.name,
            label;
        if (entity) {
            label = I18N['model'][entity][name];
            if(me.isCheckbox || me.isRadio){
                me.boxLabel = label;
            }else{
                me.fieldLabel = label;
            }
        }
    .......

代码需要在callParent方法前执行是因为在调用callParent方法后,组件已经初始化完成了,不能再通过直接赋值的方式来修改标签文本了。

代码中,先判断是否定义了实体名称,如果没有,则不设置标签文本,如果有,则从本地化文件中获取标签文本,并进行赋值操作。这里要注意的是,复选字段和单选字段是在boxLabel配置项中设置标签文本的,因而这里需要通过isCheckbox属性和isRadio属性来判断字段是复选字段还是单选字段,如果是,则将标签文本赋值给boxLabel,如果不是,则将标签文本赋值给fieldLabel。

为了更好的在本地化文件中结构化标签文本,在这里特意实体定义在model对象里。

下面来验证下该方法是否可行。在app文件夹下,新建一个名为locale的文件夹并添加一个名为zh_CN.js的脚本文件。在文件内添加以下代码:

Ext.define('PackageTest.locale.zh_CN',{
    override: 'Common.locale.Locale',

    statics: {

        model:{
            login:{
                name:'名称',
                password: '密码',
                remberMe: '记住我'
            }
        }

    }
});

在代码中,定义了一个名为login的实体,并定义了3个标签。

在app\view1\Main.js的items内添加以下代码:

items:[
        {
            xtype: 'form',
            defaults:{
                entityName: 'login'
            },
            items:[
                { xtype: 'textfield', name: 'name'},
                { xtype: 'textfield', name: 'password', inputType: 'password'},
                { xtype: 'checkboxfield', name: 'remberMe'}
            ]
        }
    ]

在代码中,定义了一个表单面板。配置项defaults为表单中的每个字段添加entityName配置项,实体的名称为login,也就是将会从本地化类的login实体获取标签文本。

代码完成后,打开app.js文件,将requires配置项修改为以下代码:

requires: [
        'Common.overrides.*',
        'Common.locale.*',
        'PackageTest.locale.*',
        'Common.util.*',
        'PackageTest.view.main.Main'
    ],

在代码中,先引用了公共包中的重写类,再引用本地化的基类,之后是具体的本地化类、公共包的功能类和主视图。

代码完成后,在终端窗口执行“sencha app refresh”命令刷新bootstrap.json,将新增的类添加到加载脚本中。这里不需要使用build命令是因为添加的类并没有对应的样式,不需要刷新样式文件,只需要刷新类的加载就行了。

在浏览器打开测试项目,可看见以下的视图:

Ext JS 6:表单字段自动从本地化类获取标签文本_package

从图中可以看到,字段已经成功获取到所需的标签文本了。这说明Common.overrides.form.field.Base已经正确运行了,正是我们所需的效果。

我们延伸一下,是否网格的列标题也可以使用这种方式来实现呢?这个也是可行的,有兴趣,可以自己研究下。

本文本的源代码:https://gitee.com/tianxiaode/PackageTest/blob/master/Readme.md