文档帮助

术语、图标和标签

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

访问级别

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

成员类型

成员语法

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

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

当原始配置对象添加到此容器时调用,无论是在 items 配置的初始化期间,还是在添加新项目时added),或 {@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 原始类型页面除外)都有一个与该类相关的元数据菜单视图。此元数据视图将具有以下一项或多项

展开和折叠示例和类成员

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

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

桌面与移动视图

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

查看类源代码

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

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'
},
//...

Mixin 也可以指定为 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 之类的大型类分解为更易于管理和更具凝聚力的部分。

作为补丁的覆盖

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

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

话虽如此,有时确实需要覆盖框架方法。最常见的情况是为了修复错误。在这种情况下,标准覆盖形式是理想的选择。实际上,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
    ],

    ...
});

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

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

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

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

命名建议

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

在覆盖中使用 requiresuses

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

使用 callParentcallSuper

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

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

虽然这在某些方面有所帮助,但不幸的是,它使绕过原始方法(作为补丁或错误修复)变得更加困难。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