文档帮助

术语、图标和标签

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

访问级别

框架类或其成员可以指定为 privateprotected。否则,类/成员为 publicPublicprotectedprivate 是访问描述符,用于传达应如何以及何时使用类或类成员。

成员类型

成员语法

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

lookupComponent ( item ) : Ext.Component
受保护的

当原始配置对象添加到此容器时调用,无论是在初始化 items 配置期间,还是在 added 新项或 {@link #insert inserted} 时调用。

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

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

参数

item :  Object

要添加的配置对象。

返回值
Ext.Component

要添加的组件。

让我们看一下成员行的每个部分

成员标志

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

类图标

- 表示框架类

- Singleton 框架类。*有关更多信息,请参阅 singleton 标志

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

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

成员图标

- 表示类型为 config 的类成员

- 表示类型为 property 的类成员

- 表示类型为 method 的类成员

- 表示类型为 event 的类成员

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

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

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

类成员快速导航菜单

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

Getter 和 Setter 方法

与类配置选项相关的 Getter 和 setter 方法将显示在方法部分以及 API 文档和成员类型菜单的 configs 部分中,就在它们所作用的配置下方。Getter 和 setter 方法文档将在 config 行中找到,以便于参考。

历史记录栏

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

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

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

搜索和过滤器

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

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

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

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

API 文档类元数据

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

展开和折叠示例和类成员

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

类成员默认在页面上折叠。您可以使用成员行左侧的箭头图标或全局使用右上角的展开/折叠全部切换按钮来展开和折叠成员。

桌面与移动视图

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

查看类源代码

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

Cmd 7.8.0


顶部

编译器友好代码指南

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

先决条件

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

编译器不是什么

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

这些工具为 JavaScript 开发人员解决了不同的问题,并且在 JavaScript 世界中非常出色,但它们不了解 Sencha 框架功能,例如用于声明类的 Ext.define

框架感知

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

这些类型的优化已显示出可以显着改善浏览器(尤其是在旧版浏览器上)“摄取” JavaScript 代码的时间。

但是,为了使编译器提供这些好处,现在重要的是要查看编译器可以“理解”并因此为您优化的编码约定。遵循本指南中描述的约定可确保您的代码能够充分利用今天的 Sencha Cmd 和未来的 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 关键字仅接受字符串文字。

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

使用字符串或 String[] 的关键字

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

  • 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 顺序。如果 mixin 具有重叠的方法或属性,并且接收类想要控制哪个 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 中提供此优化代码后启用它。

标准覆盖形式

下面是覆盖的标准形式。命名空间的选择在某种程度上是任意的,但请参见下面的建议。

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

    ...
});

用例

随着使用 Ext.define 管理覆盖的能力,新的惯用法已经出现并正在积极利用。例如,在 Sencha Architect 的代码生成器中以及框架内部,将像 Ext.Element 这样的大型类分解为更易于管理和更具凝聚力的部分。

作为补丁的覆盖

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

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

话虽如此,但有时仍有必要重写框架方法。最常见的情况是为了修复错误。“标准 Override 形式”在这种情况下非常理想。事实上,Sencha 支持有时会以这种形式向客户提供补丁。但是,一旦提供,管理此类补丁并在不再需要时删除它们,就属于先前提及的审查流程的范畴。

命名建议:
  • 在与目标顶层命名空间关联的命名空间中组织补丁。例如,“MyApp.patches” 针对 “Ext” 命名空间。如果涉及到第三方代码,则可能应选择另一个级别或命名空间以对应于其顶层命名空间。从那里开始,使用匹配的名称和子命名空间来命名 override。在前面的示例中

    Ext -> MyApp.patches).grid.Panel

作为部分类的 Override

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

使用 override,您可以清晰地管理这一点

./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,以便类的各个部分在列表中整理在一起。

作为方面的 Override

面向对象设计中基类的一个常见问题是“臃肿的基类”。发生这种情况是因为某些行为适用于所有类。但是,当不需要这些行为(或功能)时,如果它们作为某个大型基类的一部分实现,则无法轻易删除它们。

使用 override,这些功能可以收集在它们自己的层次结构中,然后可以使用 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
    ],

    ...
});

现在可以通过 require 引入此功能

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

或使用正确的 “bootstrap” 文件 (请参阅 Sencha Cmd 中的工作区)

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

命名建议

  • 通过命名空间组织生成代码与手动编辑代码。这使得可以使用通配符来引入该功能的所有方面。

在 Override 中使用 requiresuses

Override 中支持这些关键字。使用 requires 可能会限制编译器重新排序 override 代码的能力。

使用 callParentcallSuper

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

另一种看待这个问题的方式是,callParent 对于所有形式的 Ext.define(无论是类还是 override)都以相同的方式工作。

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

在未来的版本中,编译器将使用这种语义差异来执行重写方法的死代码消除。

Override 兼容性

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

最简单的用例是测试框架版本以获得兼容性

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

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

    //...
});

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

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 7.8.0