文档帮助

术语、图标和标签

许多类在使用配置对象创建(实例化)类时具有使用的快捷名称。快捷名称称为别名(如果类扩展 Ext.Component,则称为xtype)。别名/xtype 列在适用类的类名旁边以供快速参考。

访问级别

框架类或其成员可以指定为私有受保护。否则,类/成员为公共公共受保护私有是访问描述符,用于传达如何以及何时应使用类或类成员。

成员类型

成员语法

下面是一个示例类成员,我们可以对其进行剖析以显示类成员的语法(在这种情况下,从 Ext.button.Button 类中查看的 lookupComponent 方法)。

lookupComponent ( item ) : Ext.Component
受保护

在初始化items配置期间或添加新项时将原始配置对象添加到此容器时调用,或添加或{@link #insert 插入}。

此方法将传递的对象转换为实例化子组件。

当需要对子项创建应用特殊处理时,可以在子类中覆盖此方法。

参数

item :  Object

正在添加的配置对象。

返回
Ext.Component

要添加的组件。

我们来看看成员行中的每一部分

成员标志

API 文档使用许多标志来进一步传达类成员的功能和意图。标签可以用文本标签、缩写或图标表示。

类图标

- 表示框架类

- 单例框架类。*有关更多信息,请参见单例标志

- 组件类型框架类(Ext JS 框架中扩展 Ext.Component 的任何类)

- 表示类、成员或指南在当前查看的版本中是新的

成员图标

- 表示类型为 config 的类成员

- 表示类型为 property 的类成员

- 表示类型为 method 的类成员

- 表示类型为 event 的类成员

- 表示类型为 theme variable 的类成员

- 表示类型为 theme mixin 的类成员

- 表示类、成员或指南在当前查看的版本中是新的

类成员快速导航菜单

在 API 文档页面上类名称正下方是一行按钮,对应于当前类拥有的成员类型。每个按钮按类型显示成员数(此计数在应用筛选器时更新)。单击按钮将导航到该成员部分。将鼠标悬停在成员类型按钮上将显示一个弹出菜单,其中包含该类型的所有成员,以便快速导航。

Getter 和 Setter 方法

与类配置选项相关的 Getter 和 Setter 方法将显示在方法部分以及 API 文档和成员类型菜单的配置部分中,它们位于它们所使用的配置正下方。Getter 和 Setter 方法文档将位于配置行中,以便于参考。

历史记录栏

您的页面历史记录保存在本地存储中,并显示在顶部标题栏正下方(使用可用空间)。默认情况下,仅显示与您当前查看的产品/版本匹配的搜索结果。您可以通过单击历史记录栏右侧的 按钮并选择“全部”单选选项来展开显示的内容。这将在历史记录栏中显示所有产品/版本的所有近期页面。

在历史记录配置菜单中,您还将看到最近访问的页面列表。结果按“当前产品/版本”和“全部”单选选项进行筛选。单击 按钮将清除历史记录栏以及保存在本地存储中的历史记录。

如果在历史记录配置菜单中选择“全部”,则将启用“在历史记录栏中显示产品详细信息”复选框选项。选中后,每个历史记录页面的产品/版本将与历史记录栏中的页面名称一起显示。将光标悬停在历史记录栏中的页面名称上也将以工具提示的形式显示产品/版本。

搜索和筛选器

可以使用页面顶部的搜索字段搜索 API 文档和指南。

在 API 文档页面上,还有一个筛选器输入字段,它使用筛选器字符串筛选成员行。除了按字符串筛选外,您还可以按访问级别、继承和只读筛选类成员。这是使用页面顶部的复选框完成的。

API 类导航树底部的复选框筛选类列表,以包括或排除私有类。

单击空搜索字段将显示您最近的 10 次搜索,以便快速导航。

API 文档类元数据

每个 API 文档页面(Javascript 基本页面除外)都有一个与该类相关的元数据的菜单视图。此元数据视图将包含以下一个或多个

展开和折叠示例和类成员

默认情况下,可运行示例(小提琴)在页面上展开。你可以使用代码块左上角的箭头单独折叠和展开示例代码块。你还可以使用页面右上角的切换按钮切换所有示例的折叠状态。切换所有状态将在页面加载之间记住。

默认情况下,类成员在页面上折叠。你可以使用成员行左侧的箭头图标或全局使用右上角的展开/折叠所有切换按钮展开和折叠成员。

桌面 -vs- 移动视图

在较窄的屏幕或浏览器上查看文档将导致针对较小尺寸优化视图。桌面和“移动”视图之间的主要区别是

查看类源

可以通过单击 API 文档页面顶部的类名来查看类源。可以通过单击成员行右侧的“查看源”链接来查看类成员的源。

Cmd


顶部

编译器友好代码指南

Sencha Cmd 的主要组件之一是其编译器。本指南介绍如何编写代码以充分利用编译器并为未来的框架感知优化做好准备。

先决条件

建议在继续之前阅读以下指南

编译器不是什么

Sencha Cmd 编译器不是以下工具的替代品

这些工具为 JavaScript 开发人员解决了不同的问题,并且在 JavaScript 领域非常出色,但对 Sencha 框架特性(如用于声明类的 Ext.define)没有了解。

框架感知

Sencha Cmd 编译器的作用是提供框架感知优化和诊断。一旦代码通过 Sencha Cmd 编译器,它便可以用于更通用的工具。

事实证明,此类优化可以显著改善浏览器对 JavaScript 代码的“摄入”时间,尤其是在旧版浏览器上。

然而,为了让编译器提供这些好处,现在重要的是要了解编译器可以“理解”的编码约定,因此可以针对你进行优化。遵循本指南中描述的约定可确保你的代码定位于充分利用当前和未来的 Sencha Cmd。

代码组织

动态加载器和之前的 JSBuilder 始终对类的组织方式做出某些假设,但如果不遵循这些准则,它们不会受到严重影响。这些准则与 Java 非常相似。

回顾一下,这些准则如下

  • 每个 JavaScript 源文件都应在全局作用域中包含一个 Ext.define 语句。
  • 源文件的名称与定义类型的名称的最后一个部分匹配,例如包含 Ext.define("MyApp.foo.bar.Thing", ... 的源文件的名称为“Thing.js”。
  • 所有源文件都存储在基于定义类型的命名空间的文件夹结构中。例如,给定 Ext.define("MyApp.foo.bar.Thing", ...,源文件位于以“/foo/bar”结尾的路径中。

在内部,编译器将源文件和类视为基本同义词。它不会尝试拆分文件以删除不需要的类。只有完整的文件才会被选中并包含在输出中。这意味着如果源文件中的任何类是必需的,则文件中的所有类都将包含在输出中。

为了让编译器能够在类级别选择代码,必须在每个文件中只放置一个类。

类声明

Sencha 类系统提供 Ext.define 函数以启用高级面向对象编程。编译器认为 Ext.define 实际上是一种“声明式”编程形式,并相应地处理“类声明”。

显然,如果 Ext.define 被理解为声明,那么类主体的内容不能在代码中动态构建。虽然这种做法很少见,但它是一种有效的 JavaScript。但正如我们在下面的代码形式中所看到的,这与编译器理解其解析代码的能力背道而驰。动态类声明通常用于执行由编译器的其他特性更好地处理的任务。有关这些特性的详细信息,请参阅Sencha 编译器参考

编译器理解此声明式语言的以下“关键字”

  • requires
  • uses
  • extend
  • mixins
  • statics
  • alias
  • singleton
  • override
  • alternateClassName
  • xtype

为了让编译器识别你的类声明,它们需要遵循以下形式之一。

标准形式

大多数类使用如下简单的声明

Ext.define('Foo.bar.Thing', {
    // keywords go here ... such as:

    extend: '...',

    // ...
});

第二个参数是类主体,它由编译器作为类“声明”处理。

注意:在所有形式中,都在全局作用域中调用 Ext.define

包装函数形式

在某些用例中,类声明被包装在一个函数中,为类方法创建一个闭包作用域。在所有各种形式中,对于编译器来说,至关重要的是,该函数以 return 语句结尾,该语句将类主体作为对象字面量返回。编译器不识别其他技术。

函数形式

为了简化下面描述的这种技术的旧形式,Ext.define 理解,如果给定一个函数作为其第二个参数,它应该调用该函数来生成类主体。它还将对类的引用作为单个参数传递,以通过闭包范围方便地访问静态成员。在框架内部,这是闭包范围最常见的原因。

Ext.define('Foo.bar.Thing', function (Thing) {

    return {
        // keywords go here ... such as:

        extend: '...',

        // ...
    };
});

注意: 此形式仅在 Ext JS 4.1.2 及更高版本和 Sencha Touch 2.1 及更高版本中受支持。

调用函数形式

在以前的版本中,不支持“函数形式”,因此只是立即调用该函数

Ext.define('Foo.bar.Thing', function () {

    return {
        // keywords go here ... such as:

        extend: '...',

        // ...
    };
}());

调用带括号的函数形式

此形式和下一个形式通常用于安抚 JSHint(或 JSLint)之类的工具。

Ext.define('Foo.bar.Thing', (function () {

    return {
        // keywords go here ... such as:

        extend: '...',

        // ...
    };
})());

带括号的调用函数形式

立即调用“函数形式”的另一种变体,以安抚 JSHint/JSLint。

Ext.define('Foo.bar.Thing', (function () {

    return {
        // keywords go here ... such as:

        extend: '...',

        // ...
    };
}()));

关键字

类声明在其多种形式中最终包含“关键字”。每个关键字都有自己的语义,但有许多关键字具有共同的“形状”。

使用字符串的关键字

extendoverride 关键字只接受字符串文字。

这些关键字也是互斥的,因为在任何声明中只能使用一个关键字。

使用字符串或字符串数组的关键字

以下关键字都具有相同的形式

  • requires
  • uses
  • alias
  • alternateClassName
  • xtype

这些关键字支持的形式如下。

只是一个字符串

requires: 'Foo.thing.Bar',
//...

一个字符串数组

requires: [ 'Foo.thing.Bar', 'Foo.other.Thing' ],
//...

mixins 的形式

使用对象文字,给定 mixin 的名称可以加引号,也可以不加引号

mixins: {
    name: 'Foo.bar.Mixin',
    'other': 'Foo.other.Mixin'
},
//...

Mixins 也可以指定为 String[]

mixins: [
    'Foo.bar.Mixin',
    'Foo.other.Mixin'
],
//...

这种方法依赖于 mixin 类的 mixinId,但也允许接收类控制 mixin 顺序。如果 mixins 具有重叠的方法或属性,并且接收类想要控制哪个 mixin 提供重叠的方法或属性,这一点很重要。

statics 关键字

此关键字将属性或方法放在类上,而不是放在每个实例上。这必须是一个对象文字。

statics: {
    // members go here
},
// ...

singleton 关键字

此关键字在历史上仅与布尔值“true”一起使用

singleton: true,

还支持以下(冗余)用法

singleton: false,

覆盖

在 Ext JS 4.1.0 和 Sencha Touch 2.0 中,Ext.define 获得了管理覆盖的能力。从历史上看,覆盖已用于修补代码以解决错误或添加增强功能。由于执行 Ext.override 方法所需的时间,这种用法随着动态加载器的引入而变得复杂。此外,在具有许多覆盖的大型应用程序中,并非所有代码库中的覆盖都是所有页面或构建所需的(例如,如果不需要目标类)。

一旦类系统和加载器理解覆盖,这一切都发生了变化。这种趋势只会随着 Sencha Cmd 而继续。编译器理解覆盖及其依赖项影响和加载顺序问题。

将来,编译器将在消除被覆盖方法的死代码方面变得更加激进。使用下面描述的托管覆盖可以在 Sencha Cmd 中提供此优化,一旦在 Sencha Cmd 中可用。

标准覆盖形式

以下是覆盖的标准形式。命名空间的选择有点武断,但请参阅下面的建议。

Ext.define('MyApp.patches.grid.Panel', {
    override: 'Ext.grid.Panel',

    ...
});

用例

通过使用 Ext.define 来管理覆盖,新的惯用法已经开放并正在积极利用。例如,在 Sencha Architect 的代码生成器中,以及在框架内部,将大型类(如 Ext.Element)分解成更易于管理和内聚的部分。

覆盖作为补丁

覆盖作为补丁是历史用例,因此是当今实践中最常见的用例。

注意: 修补代码时要小心。虽然支持使用覆盖本身,但不支持覆盖框架方法的最终结果。每当升级到新的框架版本时,都应仔细检查所有覆盖。

也就是说,有时有必要覆盖框架方法。在这种情况下,标准覆盖形式是理想的。事实上,Sencha 支持有时会以这种形式为客户提供补丁。但是,一旦提供,管理此类补丁并在不再需要时删除它们,就是前面提到的审查过程的问题。

命名建议:
  • 将补丁组织在与目标顶层命名空间关联的命名空间中。例如,“MyApp.patches”针对“Ext”命名空间。如果涉及第三方代码,则可能应该选择另一个级别或命名空间来对应其顶层命名空间。在此基础上,使用匹配的名称和子命名空间来命名覆盖。在前面的示例中

    Ext -> MyApp.patches).grid.Panel

作为部分类的覆盖

在处理代码生成(如在 Sencha Architect 中)时,一个类通常由两部分组成:一部分是机器生成的,另一部分是人工编辑的。在某些语言中,正式支持“部分类”或“两部分类”的概念。

使用覆盖,您可以对其进行干净地管理

./foo/bar/Thing.js

Ext.define('Foo.bar.Thing', {
    // NOTE: This class is generated - DO NOT EDIT...

    requires: [
        'Foo.bar.custom.Thing'
    ],

    method: function () {
        // some generated method
    },

    ...
});

./foo/bar/custom/Thing.js

Ext.define('Foo.bar.custom.Thing', {
    override: 'Foo.bar.Thing',

    method: function () {
        this.callParent(); // calls generated method
        ...
    },

    ...
});

命名建议

  • 按命名空间组织生成的代码与手工编辑的代码。
  • 如果不按命名空间组织,请考虑使用一个通用的基本名称,并在其中一个或另一个名称上添加后缀,例如 Foo.bar.ThingOverrideFoo.bar.ThingGenerated,以便类的部分在列表中一起整理。

作为切面的覆盖

面向对象设计中基类的常见问题是“臃肿的基类”。这是因为某些行为适用于所有类。但是,如果这些行为(或特性)不需要,如果它们作为某个大型基类的一部分实现,则无法轻易地将其移除。

使用覆盖,这些特性可以收集到它们自己的层次结构中,然后可以根据需要使用 requires 来选择这些特性。

./foo/feature/Component.js

Ext.define('Foo.feature.Component', {
    override: 'Ext.Component',

    ...
});

./foo/feature/grid/Panel.js

Ext.define('Foo.feature.grid.Panel', {
    override: 'Ext.grid.Panel',

    requires: [
        'Foo.feature.Component' // since overrides do not "extend" each other
    ],

    ...
});

现在可以通过要求来使用此特性

...
requires: [
    'Foo.feature.grid.Panel'
]

或使用适当的“引导”文件(请参阅 Sencha Cmd 中的工作空间

...
requires: [
    'Foo.feature.*'
]

命名建议

  • 按命名空间组织生成的代码与手工编辑的代码。这允许使用通配符来引入特性的所有切面。

在覆盖中使用 requiresuses

这些关键字在覆盖中受支持。使用 requires 可能会限制编译器对覆盖代码进行重新排序的能力。

使用 callParentcallSuper

为了支持所有这些新的用例,Ext JS 4.0 和 Sencha Touch 2.0 中的 callParent 已增强为“调用下一个方法”。“下一个方法”可能是覆盖的方法或继承的方法。只要有下一个方法,callParent 就会调用它。

另一种查看方式是 callParent 对所有形式的 Ext.define 都起作用,无论是类还是覆盖。

虽然这在某些方面有所帮助,但不幸的是,它使得绕过原始方法(作为补丁或错误修复)变得更加困难。Ext JS 4.1 及更高版本和 Sencha Touch 2.1 及更高版本提供了一个名为 callSuper 的方法,该方法可以绕过覆盖的方法。

在将来的版本中,编译器将使用此语义差异来消除覆盖方法的死代码。

覆盖兼容性

从 4.2.2 版本开始,覆盖可以根据框架版本或其他包的版本声明其 compatibility。这对于有选择地应用补丁非常有用,当这些补丁与目标类版本不兼容时,可以安全地忽略它们。

最简单的用例是测试框架版本以进行兼容性检查

Ext.define('App.overrides.grid.Panel', {
    override: 'Ext.grid.Panel',

    compatibility: '4.2.2', // only if framework version is 4.2.2

    //...
});

数组被视为 OR,因此如果任何规范匹配,则覆盖兼容。

Ext.define('App.overrides.some.Thing', {
    override: 'Foo.some.Thing',

    compatibility: [
        '4.2.2',
        '[email protected]'
    ],

    //...
});

要要求所有规范都匹配,可以提供一个对象

Ext.define('App.overrides.some.Thing', {
    override: 'Foo.some.Thing',

    compatibility: {
        and: [
            '4.2.2',
            '[email protected]'
        ]
    },

    //...
});

因为对象形式只是一个递归检查,所以这些对象可以嵌套

Ext.define('App.overrides.some.Thing', {
    override: 'Foo.some.Thing',

    compatibility: {
        and: [
            '4.2.2',  // exactly version 4.2.2 of the framework *AND*
            {
                // either (or both) of these package specs:
                or: [
                    '[email protected]',
                    '[email protected]+'
                ]
            }
        ]
    },

    //...
});

有关版本语法的详细信息,请参阅 Ext.VersioncheckVersion 方法。

结论

随着 Sencha Cmd 的不断发展,它不断引入新的诊断消息,以帮助指出与这些准则的偏差。

一个好的开始是了解此信息如何帮助告知您自己的内部代码样式指南和实践。

后续步骤

Cmd