许多类在使用配置对象创建(实例化)时使用简写名称。简写名称称为别名
(如果类扩展了 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
,则标记为可阻止的事件将不会触发- 表示框架类
- 单例框架类。*有关更多信息,请参阅单例标志
- 组件类型框架类(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 的强大补充。
它们共同使您能够用更少的代码做更多的事情,并以更具声明性的方式编写,同时帮助您保持清晰的关注点分离。
视图模型是一个管理数据对象的类。然后,它允许对这些数据感兴趣的人绑定到它,并在数据发生变化时收到通知。视图模型与视图控制器类似,由引用它的视图拥有。由于视图模型与视图相关联,因此它们也能够链接到祖先组件在组件层次结构中拥有的父视图模型。这允许子视图简单地“继承”其父视图模型的数据。
组件有一个bind
配置,允许它们将许多配置与视图模型中的数据关联起来。使用绑定,您可以确保适当的组件配置将在绑定值发生变化时调用其设置方法 - 无需自定义事件处理程序。
在本指南中,我们将通过一些示例来展示 ViewModel 和数据绑定的强大功能。
理解绑定和 ViewModel 的最佳方式可能是查看在组件上使用绑定的各种方法。这是因为组件是数据绑定的主要使用者,并且组件对于 Ext JS 开发人员来说是熟悉的。但是,为了使绑定起作用,我们需要一个 ViewModel,因此我们现在将引用一个并稍后定义它。
组件的绑定是将数据从 Ext.app.ViewModel 连接到组件的配置属性的过程。组件拥有的任何配置都可以绑定,只要它具有 setter 方法。例如,由于 Ext.panel.Panel 上有一个 setTitle()
方法,因此您可以绑定到 title
配置。
在本例中,我们将根据 ViewModel 的 data
的结果设置面板的 width
。我们可以将数据绑定到 width
,因为 setWidth()
是 Ext.panel.Panel
可以使用的方法。
Ext.create('Ext.panel.Panel', {
title: 'Simple Form',
viewModel: {
type: 'test' // we will define the "test" ViewModel soon
},
bind: {
html: '<p>Hello {name}</p>',
width: '{someWidth}'
}
});
用于绑定值的语法与 Ext.Template 非常相似。您可以在花括号内将文本放在标记周围。您也可以使用格式化程序,就像使用 Ext.Template
一样。但是,与 Ext.Template
不同,当模板是一个单独的标记(如 '{someWidth}')时,它的值将被直接传递。也就是说,它不会被转换为字符串。
我们将在后面看到 name
和 someWidth
的数据是如何定义的。上面的示例只是展示了数据如何被组件使用。
您可能想要绑定的许多配置都是布尔值,例如可见(或 hidden
)、disabled
、checked
和 pressed
。绑定模板支持在模板中“内联”布尔否定。其他形式的代数被降级为公式(见下文),但布尔反转很常见,因此有专门的规定。例如
Ext.create('Ext.panel.Panel', {
title: 'Simple Form',
viewModel: {
type: 'test'
},
items: [{
xtype: 'button',
bind: {
hidden: '{!name}' // negated
}
}]
});
这也突出了单标记模板中的值如何不会被转换为字符串。在上面,虽然“name”是一个字符串值,但它使用“!”被否定,并成为一个布尔值,然后传递给按钮上的 setHidden
方法。
绑定配置属性将始终覆盖在组件上静态设置的配置,只要绑定结果可用。换句话说,绑定数据将始终优先于静态配置值,但可能会延迟以获取该数据。
Ext.create('Ext.panel.Panel', {
title: 'Simple Form',
viewModel: {
type: 'test'
},
bind: {
title: 'Hello {name}'
}
});
一旦“name”的绑定被传递,"Simple Form" 标题将被替换。
绑定最有用的一部分之一是,具有 viewModel 的组件的所有子组件都可以访问其容器的数据。
在本例中,您可以看到表单的子项可以绑定到其容器的 viewModel。
Ext.create('Ext.panel.Panel', {
title: 'Simple Form',
viewModel: {
type: 'test'
},
layout: 'form',
defaultType: 'textfield',
items: [{
fieldLabel: 'First Name',
bind: '{firstName}' // uses "test" ViewModel from parent
},{
fieldLabel: 'Last Name',
bind: '{lastName}'
}]
});
bind 配置还允许双向数据绑定,这意味着视图和模型之间的数据实时同步。在视图中进行的任何数据更改都会自动写回模型。这会自动更新可能绑定到相同数据的任何其他组件。注意:并非所有配置都会在更改时将它们的值发布到 ViewModel。
在 publish
和 twoWayBindable
数组中定义的配置将把更改发布回 ViewModel。值也可以使用 publishState
方法在组件/应用程序逻辑中发布。
在上面的示例中,因为“firstName”和“lastName”属性绑定到文本字段,所以输入中的更改将被写回 ViewModel。要了解所有这些是如何连接的,现在是完成示例并定义 ViewModel 的时候了。
Ext.define('MyApp.view.TestViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.test', // connects to viewModel/type below
data: {
firstName: 'John',
lastName: 'Doe'
},
formulas: {
// We'll explain formulas in more detail soon.
name: function (get) {
var fn = get('firstName'), ln = get('lastName');
return (fn && ln) ? (fn + ' ' + ln) : (fn || ln || '');
}
}
});
Ext.define('MyApp.view.TestView', {
extend: 'Ext.panel.Panel',
layout: 'form',
// Always use this form when defining a view class. This
// allows the creator of the component to pass data without
// erasing the ViewModel type that we want.
viewModel: {
type: 'test' // references alias "viewmodel.test"
},
bind: {
title: 'Hello {name}'
},
defaultType: 'textfield',
items: [{
fieldLabel: 'First Name',
bind: '{firstName}'
},{
fieldLabel: 'Last Name',
bind: '{lastName}'
},{
xtype: 'button',
text: 'Submit',
bind: {
hidden: '{!name}'
}
}]
});
Ext.onReady(function () {
Ext.create('MyApp.view.TestView', {
renderTo: Ext.getBody(),
width: 400
});
});
当显示上面的面板时,我们可以看到文本字段中的更改反映在面板的 title
以及“Submit”按钮的 hidden
状态中。
有时组件的状态,例如复选框的 checked
状态或网格的选定记录,对其他组件很有趣。当为组件分配一个 reference
来标识它时,该组件将在 ViewModel 中发布一些关键属性。
在本例中,我们有“Admin Key”文本字段的 disabled 配置绑定到复选框的 checked 状态。这会导致文本字段被禁用,直到复选框被选中。这种行为非常适合这种动态表单
Ext.create('Ext.panel.Panel', {
title: 'Sign Up Form',
viewModel: {
type: 'test'
},
items: [{
xtype: 'checkbox',
boxLabel: 'Is Admin',
reference: 'isAdmin'
},{
xtype: 'textfield',
fieldLabel: 'Admin Key',
bind: {
disabled: '{!isAdmin.checked}'
}
}]
});
到目前为止,我们已经看到了三种基本的绑定描述符形式
{firstName}
- 直接绑定到 ViewModel 中的某个值。此值会直接传递,因此可能以任何类型的数据到达。
Hello {name}
- 绑定模板始终通过插入各种绑定表达式的文本值来生成字符串。绑定模板也可以使用格式化程序,就像普通的 Ext.Template
一样,例如:'Hello {name:capitalize}'。
{!isAdmin.checked}
- 直接绑定的否定形式,对于绑定到布尔型配置属性很有用。
除了这些基本形式之外,您还可以使用一些专门形式的绑定描述符。
如果将对象或数组作为绑定描述符给出,ViewModel 将生成一个形状相同但各种属性被其绑定结果替换的对象或数组。例如
Ext.create('Ext.Component', {
bind: {
data: {
fname: '{firstName}',
lname: '{lastName}'
}
}
});
这将组件的“data”配置设置为一个对象,该对象具有两个属性,其值从 ViewModel 设置。
当需要特定记录时,例如 id
为 42 的“User”,绑定描述符是一个对象,但具有“reference”属性。例如
Ext.create('Ext.Component', {
bind: {
data: {
reference: 'User',
id: 42
}
}
});
在这种情况下,组件的 tpl
将在加载后接收 User 记录。这目前需要使用 Ext.data.Session
。
类似于记录绑定,也可以绑定到关联,例如 User 的 Address 记录
Ext.create('Ext.Component', {
bind: {
data: {
reference: 'User',
id: 42,
association: 'address'
}
}
});
在这种情况下,组件的 tpl
将在加载后接收 User 的“address”记录。这目前也需要使用 Ext.data.Session
。
绑定描述符的最终形式用于描述绑定选项。以下示例展示了如何仅接收一个绑定值,然后自动断开连接。
Ext.create('Ext.Component', {
bind: {
data: {
bindTo: '{name}',
single: true
}
}
});
bindTo
属性是绑定描述符对象中的第二个保留名称(第一个是 reference
)。当存在时,它表示 bindTo
的值是实际的绑定描述符,其他属性是绑定的配置选项。
目前支持的另一个绑定选项是 deep
。此选项用于绑定到对象,以便在该对象的任何属性更改时,而不是仅更改引用本身时,绑定将收到通知。当绑定到组件的 data
配置时,这将非常有用,因为这些配置通常接收对象。
Ext.create('Ext.Component', {
bind: {
data: {
bindTo: '{someObject}',
deep: true
}
}
});
现在我们已经了解了组件如何使用 ViewModel,并对 ViewModel 的外观有了一定的了解,现在是时候更多地了解 ViewModel 及其提供的功能了。
如前所述,ViewModel 是一个用于底层 data
对象的管理器。绑定语句所消耗的是该对象的内容。从父 ViewModel 到其子 ViewModel 的数据继承利用了 JavaScript 原型链。这将在 ViewModel 内部机制 指南中详细介绍,但简而言之,子 ViewModel 的 data
对象以其父 ViewModel 的 data
对象作为其原型。
除了保存数据和提供绑定之外,ViewModel 还提供了一种方便的方法来从其他数据计算数据,称为 formulas
。公式允许您将数据依赖关系封装在 ViewModel 中,并使您的视图能够专注于声明其结构。
换句话说,ViewModel 中的数据不会改变,但可以通过使用公式进行转换来以不同的方式显示。这类似于传统数据模型的字段如何使用 convert
配置。
在前面的示例中,我们看到了一个简单的“name”公式。在这种情况下,“name”公式只是一个函数,它将ViewModel中的另外两个值“firstName”和“lastName”组合在一起。
公式也可以使用其他公式的结果,就好像结果只是另一个数据属性一样。例如
Ext.define('MyApp.view.TestViewModel2', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.test2',
formulas: {
x2y: function (get) {
return get('x2') * get('y');
},
x2: function (get) {
return get('x') * 2;
}
}
});
“x2”公式使用“x”属性将“x2”定义为“x * 2”。“x2y”公式同时使用“x2”和“y”。此定义意味着如果“x”发生变化,“x2”将重新计算,然后“x2y”也会重新计算。但是如果“y”发生变化,则只需要重新计算“x2y”。
在上面的示例中,公式的依赖关系是通过检查函数找到的,但这并不总是最佳解决方案。可以使用显式绑定语句,它将在绑定中的所有值都出现时返回一个简单对象。
Ext.define('MyApp.view.TestViewModel2', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.test2',
formulas: {
something: {
bind: {
x: '{foo.bar.x}',
y: '{bar.foo.thing.zip.y}'
},
get: function (data) {
return data.x + data.y;
}
}
}
});
当公式可逆时,我们还可以定义一个set
方法,该方法在设置值时被调用(例如通过双向绑定)。由于“this”指针是ViewModel,因此set
方法可以调用this.set()
来设置ViewModel中的适当属性。
下面的TestViewModel的修订版本展示了如何将“name”定义为双向公式。
Ext.define('MyApp.view.TestViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.test',
formulas: {
name: {
get: function (get) {
var fn = get('firstName'), ln = get('lastName');
return (fn && ln) ? (fn + ' ' + ln) : (fn || ln || '');
},
set: function (value) {
var space = value.indexOf(' '),
split = (space < 0) ? value.length : space;
this.set({
firstName: value.substring(0, split),
lastName: value.substring(split + 1)
});
}
}
}
});
有了ViewModel、公式和数据绑定的强大功能,很容易过度使用或滥用这些机制,从而创建一个难以理解或调试的应用程序,或者更新速度很慢或内存泄漏。为了帮助避免这些问题,并充分利用ViewModel,以下是一些推荐的技术
在配置viewModel时始终使用以下形式。这很重要,因为配置系统合并配置值的方式。使用这种形式,在合并过程中“type”属性将被保留。
Ext.define('MyApp.view.TestView', {
//...
viewModel: {
type: 'test'
},
});
使名称清晰明了,尤其是在高级ViewModel中。在JavaScript中,我们依赖于文本搜索,因此选择可以找到用法的名称。使用某个属性的代码越多,选择有意义甚至唯一的名称就越重要。
不要将数据嵌套在对象中比必要更深。存储在ViewModel中的多个顶级对象与一个具有大量嵌套子对象的单个对象相比,需要更少的簿记。此外,这将有助于使对这些信息的依赖关系比许多组件依赖于某个大型包含对象时更明显。有理由共享对象,但请记住ViewModel只是一个托管对象,因此您也可以使用它的属性。
使用子ViewModel允许数据与需要它的组件一起清理。如果您将所有数据都放在高级ViewModel中,那么即使需要它的子视图已被销毁,这些数据也很可能永远不会被删除。相反,为子视图创建ViewModel,并将数据传递到其ViewModel中。
除非真正需要,否则不要创建子ViewModel。每个ViewModel实例都需要时间来创建,并需要内存来管理。如果子视图不需要自身独有的数据,它可以简单地使用从其容器继承的ViewModel。请参阅前面的建议,因为在需要时创建子ViewModel比污染父ViewModel并有效地泄漏内存要好。
使用公式而不是重复绑定。如果您了解了公式是如何将多个绑定值的组合在一起的方式,您可能会发现使用公式将有助于减少与在许多地方直接使用这些相同值相比的依赖关系数量。例如,一个具有3个依赖关系和4个用户的公式在ViewModel中需要跟踪3 + 4 = 7
个依赖关系。相比之下,4个用户具有这3个依赖关系,我们将有3 * 4 = 12
个依赖关系。跟踪的依赖关系越少,使用的内存就越少,处理它们的时间就越少。
不要将公式链得太深。这与其说是运行时成本问题,不如说是代码清晰度问题。链式公式可能会掩盖数据和组件之间的连接,从而难以理解正在发生的事情。
双向公式必须稳定。假设公式“foo”是值“bar”的计算结果。当设置“foo”时,它将通过反转其get方法中的公式来设置“bar”。如果get方法将为“foo”生成与现在正在设置的完全相同的值,则结果是稳定的。如果没有,该过程将循环,直到达到稳定点,或者将无限期地继续下去。两种结果都不太可能令人满意。
有关ViewModel的更多信息,请花几分钟时间查看我们的ViewModel 内部指南。