许多类在使用配置对象创建(实例化)类时都有快捷名称。快捷名称被称为 别名
(如果类扩展了 Ext.Component,则称为 xtype
)。别名/xtype 列在适用类的类名旁边,以便快速参考。
框架类或其成员可以指定为 private
或 protected
。否则,类/成员为 public
。Public
、protected
和 private
是访问描述符,用于传达应该如何以及何时使用类或类成员。
Public 类和类成员可供任何其他类或应用程序代码使用,并且在主要产品版本中可以作为稳定且持久的内容依赖。公共类和成员可以通过子类安全地扩展。
Protected 类成员是稳定的 public
成员,旨在由拥有类或其子类使用。受保护的成员可以通过子类安全地扩展。
Private 类和类成员在框架内部使用,不供应用程序开发人员使用。私有类和成员可能会随时更改或从框架中省略,恕不另行通知,并且不应在应用程序逻辑中依赖它们。
static
标签。*请参阅下面的静态。下面是一个示例类成员,我们可以对其进行剖析,以显示类成员的语法(在本例中是从 Ext.button.Button 类查看的 lookupComponent 方法)。
让我们看一下成员行的每个部分
lookupComponent
)( item )
)Ext.Component
)。对于不返回除 undefined
以外的任何内容的方法,可以省略此项,或者可以显示为用斜杠 /
分隔的多个可能值,表示返回的内容可能取决于方法调用的结果(即,如果 get 方法调用成功,则方法可能返回 Component;如果失败,则返回 false
,这将显示为 Ext.Component/Boolean
)。PROTECTED
- 请参阅下面的标志部分)Ext.container.Container
)。如果成员源自当前类,则源类将显示为蓝色链接;如果它从祖先类或混合类继承,则显示为灰色。view source
)item : Object
)。undefined
以外的值,则“返回值”部分将注明返回的类或对象类型以及描述(示例中为 Ext.Component
)。Available since 3.4.0
- 示例中未显示)就在成员描述之后Defaults to: false
)API 文档使用许多标志来进一步传达类成员的功能和意图。标签可以用文本标签、缩写或图标表示。
classInstance.method1().method2().etc();
false
,则标记为可阻止的事件将不会触发- 表示框架类
- Singleton 框架类。*有关更多信息,请参阅 singleton 标志
- 组件类型的框架类(Ext JS 框架中扩展 Ext.Component 的任何类)
- 表示类、成员或指南在当前查看的版本中是新的
- 表示 config
类型的类成员
- 表示 property
类型的类成员
- 表示 method
类型的类成员
- 表示 event
类型的类成员
- 表示 theme variable
类型的类成员
- 表示 theme mixin
类型的类成员
- 表示类、成员或指南在当前查看的版本中是新的
在 API 文档页面上的类名正下方是一行按钮,对应于当前类拥有的成员类型。每个按钮显示按类型划分的成员计数(此计数在应用过滤器时会更新)。单击按钮将导航到该成员部分。将鼠标悬停在成员类型按钮上将显示该类型的所有成员的弹出菜单,以便快速导航。
与类配置选项相关的 Getter 和 setter 方法将显示在方法部分以及 API 文档和成员类型菜单的配置部分中,就在它们所使用的配置下方。Getter 和 setter 方法文档将在配置行中找到,以便于参考。
您的页面历史记录保存在本地存储中,并显示在顶部标题栏正下方(使用可用的实际空间)。默认情况下,显示的唯一搜索结果是与您当前查看的产品/版本匹配的页面。您可以通过单击历史记录栏右侧的 按钮并选择“全部”单选按钮来扩展显示的内容。这将显示历史记录栏中所有产品/版本的所有最近页面。
在历史记录配置菜单中,您还将看到最近访问页面的列表。结果按“当前产品/版本”和“全部”单选按钮过滤。单击 按钮将清除历史记录栏以及本地存储中保存的历史记录。
如果在历史记录配置菜单中选择“全部”,则将启用“在历史记录栏中显示产品详细信息”复选框选项。选中后,每个历史页面的产品/版本将与历史记录栏中的页面名称一起显示。将光标悬停在历史记录栏中的页面名称上也会将产品/版本显示为工具提示。
可以使用页面顶部的搜索字段搜索 API 文档和指南。
在 API 文档页面上,还有一个过滤器输入字段,用于使用过滤器字符串过滤成员行。除了按字符串过滤外,您还可以按访问级别、继承和只读过滤类成员。这是通过使用页面顶部的复选框完成的。
API 类导航树底部的复选框过滤类列表以包含或排除私有类。
单击空的搜索字段将显示您最近 10 次的搜索,以便快速导航。
每个 API 文档页面(JavaScript 原始页面除外)都有一个元数据菜单视图,该元数据与该类相关。此元数据视图将具有以下一项或多项
Ext.button.Button
类具有 Ext.Button
的备用类名)。备用类名通常为了向后兼容性而维护。可运行的示例 (Fiddles) 默认在页面上展开。您可以使用代码块左上角的箭头单独折叠和展开示例代码块。您还可以使用页面右上角的切换按钮切换所有示例的折叠状态。切换所有状态将在页面加载之间记住。
类成员默认在页面上折叠。您可以使用成员行左侧的箭头图标或全局使用右上角的展开/折叠所有切换按钮来展开和折叠成员。
在较窄的屏幕或浏览器上查看文档将导致针对较小外形尺寸优化的视图。桌面视图和“移动”视图之间的主要区别是
可以通过单击 API 文档页面顶部的类名来查看类源代码。可以通过单击成员行右侧的“查看源代码”链接来查看类成员的源代码。
Ext JS 为您在应用程序架构中使用提供了一些令人兴奋的改进。我们添加了对 ViewModels 和 MVVM 以及 ViewControllers 的支持,以增强 MVC 应用程序。最棒的是,这些选择不是互斥的,因此您可以逐步引入这些功能,甚至可以混合使用它们。
Controller 是从 Ext.app.Controller 派生的类。这些控制器使用类似 CSS 的选择器(称为“组件查询”)来匹配组件并响应其事件。它们还使用“refs”来选择和检索组件实例。
这些控制器在应用程序启动时创建,并在应用程序的生命周期内保持存在。在其生命周期内,控制器感兴趣的视图将会来来去去。甚至可能存在控制器管理的视图的多个实例。
对于大型应用程序,这些技术可能会带来某些挑战。
在这样的环境中,视图和控制器可能由多个开发团队编写并集成到最终应用程序中。确保控制器仅对其预期的视图做出反应可能很困难。此外,开发人员通常希望限制在应用程序启动时创建的控制器的数量。虽然通过一些努力可以延迟创建控制器,但它们无法销毁,因此即使不再需要它们,它们仍然存在。
虽然 Ext JS 5+ 向后兼容旧版应用程序级控制器,但它引入了一种旨在应对这些挑战的新型控制器:Ext.app.ViewController。ViewController 通过以下方式实现此目的
对于 ViewControllers 的目的,我们可以只看两个示例。第一个是在视图中的子项上基本使用监听器配置
Ext.define('MyApp.view.foo.Foo', {
extend: 'Ext.panel.Panel',
xtype: 'foo',
controller: 'foo',
items: [{
xtype: 'textfield',
fieldLabel: 'Bar',
listeners: {
change: 'onBarChange' // no scope given here
}
}]
});
Ext.define('MyApp.view.foo.FooController', {
extend: 'Ext.app.ViewController',
alias: 'controller.foo',
onBarChange: function (barTextField) {
// called by 'change' event
}
});
上面对监听器的使用显示了一个命名的事件处理程序 (onBarChange
),没有指定“scope”。在内部,事件系统将 Bar 文本字段的默认 scope 解析为其拥有的 ViewController。
从历史上看,监听器配置保留供组件的创建者使用,那么视图如何监听自己的事件,或者可能监听其基类触发的事件?答案是我们需要使用显式 scope
Ext.define('MyApp.view.foo.Foo', {
extend: 'Ext.panel.Panel',
xtype: 'foo',
controller: 'foo',
listeners: {
collapse: 'onCollapse',
scope: 'controller'
},
items: [{
...
}]
});
上面的示例利用了 Ext JS 中的两个新功能:命名 scope 和声明式监听器。我们将在此处重点关注命名 scope。命名 scope 有两个有效值:“this”和“controller”。在编写 MVC 应用程序时,我们几乎总是使用“controller”,这显然会导致查看该视图的 ViewController(而不是创建实例的视图的 ViewController)。
由于视图是 Ext.Component 的一种类型,我们已为此视图分配了“xtype”,这使其他视图能够以与此视图创建其文本字段相同的方式创建此视图的实例。要了解这是如何结合在一起的,请考虑一个使用此视图的视图。例如
Ext.define('MyApp.view.bar.Bar', {
extend: 'Ext.panel.Panel',
xtype: 'bar',
controller: 'bar',
items: [{
xtype: 'foo',
listeners: {
collapse: 'onCollapse'
}
}]
});
在这种情况下,Bar 视图正在创建 Foo 视图的实例作为其项目之一。此外,它正在监听 collapse 事件,就像 Foo 视图一样。Foo 视图声明的监听器将在 Foo 的 ViewController 上触发,而 Bar 视图中声明的监听器将在 Bar 的 ViewController 上触发。
编写控制器逻辑时最常见的遗留问题之一是如何获得完成特定操作所需的组件。像这样简单的东西
Ext.define('MyApp.view.foo.Foo', {
extend: 'Ext.panel.Panel',
xtype: 'foo',
controller: 'foo',
tbar: [{
xtype: 'button',
text: 'Add',
handler: 'onAdd'
}],
items: [{
xtype: 'grid',
...
}]
});
Ext.define('MyApp.view.foo.FooController', {
extend: 'Ext.app.ViewController',
alias: 'controller.foo',
onAdd: function () {
// ... get the grid and add a record ...
}
});
但是应该如何获取网格组件呢?所有技术都要求您在网格上放置一些可识别的属性,以便唯一标识它。较旧的技术使用“id”配置(和 getCmp)或“itemId”配置(使用“refs”或某些组件查询方法)。“id”的优点是查找速度快,但由于这些标识符必须在整个应用程序和 DOM 中都是唯一的,因此这通常是不希望的。使用“itemId”和某种形式的查询更灵活,但需要执行搜索才能找到所需的组件。
使用 reference
配置,我们只需将“reference”添加到网格并使用 lookupReference
来获取它
Ext.define('MyApp.view.foo.Foo', {
extend: 'Ext.panel.Panel',
xtype: 'foo',
controller: 'foo',
tbar: [{
xtype: 'button',
text: 'Add',
handler: 'onAdd'
}],
items: [{
xtype: 'grid',
reference: 'fooGrid'
...
}]
});
Ext.define('MyApp.view.foo.FooController', {
extend: 'Ext.app.ViewController',
alias: 'controller.foo',
onAdd: function () {
var grid = this.lookupReference('fooGrid');
}
});
这类似于分配 itemId “fooGrid” 并执行:“this.down(‘#fooGrid’)”。然而,幕后的区别非常显着。首先,reference 配置指示组件向其拥有的视图注册自身(在这种情况下,通过 ViewController 的存在来识别)。其次,lookupReference
方法只是查询缓存以查看是否需要刷新引用(例如,由于容器上的添加或删除)。如果一切正常,它只会从缓存中返回引用。或者,用伪代码表示
lookupReference: (reference) {
var cache = this.references;
if (!cache) {
Ext.fixReferences(); // fix all references
cache = this.references; // now the cache is valid
}
return cache[reference];
}
换句话说,没有搜索,并且当需要时,一次性修复了因从容器中添加或删除项目而损坏的链接。正如我们将在下面看到的,这种方法除了效率之外还有其他好处。
选择器与控制器 refs
配置的结合使用非常灵活,但同时也存在一定的风险。这些选择器“看到”组件层次结构所有级别的所有内容这一事实既强大又容易出错。例如,控制器在隔离运行时可能 100% 工作,但一旦引入其他视图就会失败,因为其选择器与新视图具有不需要的匹配项。
这些问题可以通过遵循某些实践来管理,但是当将监听器和引用与 ViewController 一起使用时,这些问题根本不可能发生。这是因为监听器和引用配置仅与其拥有的 ViewController 连接。视图可以自由选择在该视图中唯一的任何引用值,因为知道这些名称不会暴露给视图的创建者。
同样,监听器在其拥有的 ViewController 上解析,并且不会意外地分派到其他控制器中具有错误选择器的事件处理程序。虽然监听器通常优于选择器,但在需要基于选择器的方法的那些情况下,这两种机制可以很好地协同工作。
为了完成此模型,视图需要触发可以由其拥有的视图的 ViewController 使用的事件。ViewController 中有一个辅助方法用于此目的:fireViewEvent
。例如
Ext.define('MyApp.view.foo.FooController', {
extend: 'Ext.app.ViewController',
alias: 'controller.foo',
onAdd: function () {
var record = new MyApp.model.Thing();
var grid = this.lookupReference('fooGrid');
grid.store.add(record);
this.fireViewEvent('addrecord', this, record);
}
});
这为该视图的创建者启用了标准形式的监听器
Ext.define('MyApp.view.bar.Bar', {
extend: 'Ext.panel.Panel',
xtype: 'bar',
controller: 'bar',
items: [{
xtype: 'foo',
listeners: {
collapse: 'onCollapse',
addrecord: 'onAddRecord'
}
}]
});
在 Ext JS 4.2 中,通过引入事件域,MVC 事件调度器被通用化。这些事件域拦截事件,并在事件触发时将它们调度到由选择器匹配控制的控制器。 “component”事件域具有完整的组件查询选择器,而其他域具有更有限的选择器。
使用 Ext JS 5+,每个 ViewController 创建一种称为“view”事件域的新型事件域的实例。此事件域允许 ViewControllers 使用标准 listen
和 control
方法,同时将其范围隐式地限制为其视图。它还添加了一个特殊的选择器来匹配视图本身
Ext.define('MyApp.view.foo.FooController', {
extend: 'Ext.app.ViewController',
alias: 'controller.foo',
control: {
'#': { // matches the view itself
collapse: 'onCollapse'
},
button: {
click: 'onAnyButtonClick'
}
}
});
以上可以看出监听器和选择器之间的关键区别。“button”选择器将匹配此视图或任何子视图中的任何按钮,无论深度如何,即使该按钮属于曾孙视图。换句话说,基于选择器的处理程序不尊重封装边界。此行为与以前的 Ext.app.Controller 行为一致,并且在有限的情况下可能是一种有用的技术。
最后,这些事件域尊重嵌套,并有效地将事件“冒泡”到视图层次结构中。也就是说,当事件触发时,它首先传递给任何标准监听器。然后,它传递给其拥有的 ViewController,然后传递给其父 ViewController(如果有),直到层次结构向上。最终,事件传递到标准“component”事件域,以便由 Ext.app.Controller 派生的控制器处理。
大型应用程序的常用技术是在首次需要时动态创建控制器。这可以帮助减少应用程序的加载时间,并通过不激活所有潜在的控制器来帮助运行时性能。以前版本中对此的限制是,一旦创建,这些控制器将保持在应用程序中处于活动状态。无法销毁它们并释放其资源。同样,这并没有改变控制器可以具有任意数量的关联视图(包括无)的现实。
但是,ViewController 在组件生命周期的早期创建,并在整个生命周期内绑定到该视图。当该视图销毁时,ViewController 也同样销毁。这意味着 ViewController 不再被迫管理没有视图或多个视图的状态。
这种一对一的关系意味着引用跟踪得到了简化,并且不再容易泄漏已销毁的组件。ViewController 可以实现以下任何方法,以便在其生命周期的关键点执行任务
callParent
)。我们认为 ViewControllers 将大大简化您的 MVC 应用程序。它们与 ViewModels 也非常配合使用,因此您可以结合这些方法及其各自的优势。