许多类在使用配置对象创建(实例化)类时都有快捷名称。快捷名称被称为 alias
(别名)(如果类扩展了 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
(自 3.4.0 版本起可用) - 示例中未显示),紧随成员描述之后Defaults to: false
(默认为: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
的备用类名)。备用类名通常为了向后兼容性而维护。可运行的示例 (Fiddle) 默认在页面上展开。您可以使用代码块左上角的箭头单独折叠和展开示例代码块。您还可以使用页面右上角的切换按钮切换所有示例的折叠状态。切换所有状态将在页面加载之间记住。
类成员默认在页面上折叠。您可以使用成员行左侧的箭头图标或使用右上角的展开/折叠全部切换按钮全局展开和折叠成员。
在较窄的屏幕或浏览器上查看文档将导致针对较小外形尺寸优化的视图。桌面和“移动”视图之间的主要区别在于
可以通过单击 API 文档页面顶部的类名来查看类源代码。可以通过单击成员行右侧的“view source”(查看源代码)链接来查看类成员的源代码。
在普通网站上,用户通过单击链接或填写表单在不同页面之间导航。但是,在单页应用程序中,用户的交互不会加载新页面。相反,它在单个页面中处理,组件对该交互做出反应。那么,如何仍然允许用户使用浏览器的前进和后退按钮?答案是使用 Ext JS 的 Router 消化 URI 哈希更改。
路由可用于通过使用浏览器历史堆栈来跟踪应用程序状态。路由还允许深度链接到应用程序,从而允许直接链接到应用程序的特定部分。这对用户非常有用,因此他们可以为您的应用程序添加书签,甚至可以将链接发送给其他人以直接访问应用程序的该部分。
路由不应用于存储任何数据或会话,数据应存储在持久性数据源中,例如 cookie 或本地存储。路由仅是一种跟踪应用程序状态的方式。
浏览器使用 URI 导航互联网,URI 由许多部分组成。让我们看一个示例 URI
https://www.example.com/apps/users#user=1234
这应该看起来相对熟悉。但是,您可能不认识 #user=1234
。URI 的这一部分称为“hash”(哈希)或片段标识符。有关哈希的更多信息,请阅读此资源 http://en.wikipedia.org/wiki/Fragment_identifier。此哈希提供了一种应用程序控制浏览器历史堆栈的方式,而无需重新加载当前页面。随着哈希的变化,浏览器将整个 URI 添加到历史堆栈中,然后允许您利用浏览器的前进/后退按钮来遍历 URI,包括可能已更改的哈希。例如,如果您将哈希更新为
https://www.example.com/apps/users#user/5678
浏览器会触发一个 hashchange
事件,然后我们可以在应用程序中使用它。然后,用户可以单击后退按钮返回到 #user=1234
哈希。然后,此通知允许您对应用程序中的更改做出反应。重要的是要提到哈希不会发送到服务器。哈希通常在客户端对 URI 的解释中被消化。Ext JS Router 依赖于浏览器的哈希功能来允许应用程序状态跟踪和深度链接。
Router 类是 Ext JS 的一个新增功能,旨在使 MVC 应用程序中的哈希更改解释非常简单。我们一直都有 Ext.util.History,您可以使用它来对哈希更改做出反应。但是,此 Ext.util.History
提供了更手动的过程,并且需要一个合适的 Router 类。Router 通过在视图控制器中定义路由,为 Ext JS 5+ MVC 应用程序提供简单的集成。路由是一个与哈希匹配的字符串,并允许在您的 Ext 应用程序中进行深度链接。这是一个实现 Router 的基本示例控制器
Ext.define('MyApp.view.main.MainController', {
extend : 'Ext.app.ViewController',
routes : {
'users' : 'onUsers'
},
onUsers : function () {
//...
}
});
此路由将对 #users
哈希做出反应,并将执行作用域限定为控制器实例的 onUsers
方法。如您所见,routes
配置放置在 config
对象中,而不是在根级别。
要更新哈希,控制器有一个 redirectTo
方法。
this.redirectTo('user/1234');
这将更新哈希为 "#user/1234"
,并且任何配置为识别哈希的路由都将执行。
redirectTo
方法还接受第二个参数以传入 options
(选项)。选项是
force
(强制) 如果为 true
(真),这将强制 Router 做出反应,即使地址栏中的哈希与传递给 redirectTo
的哈希相同。replace
(替换) 默认情况下,哈希将被更改,并且将在浏览器的历史记录中创建一个新条目。这意味着浏览器的后退按钮可以返回到上一个哈希。如果为 true
(真),则浏览器历史记录中的当前条目将被传递给 redirectTo
的哈希替换。注意: _为了向后兼容性,options
可以是布尔值。在这种情况下,它设置的是 force
选项。
当应用程序启动时,如果未提供默认哈希,则可以配置为添加默认哈希。例如,如果应用程序在使用 #home
哈希时显示仪表板,您可能希望在 URI 中没有其他哈希时添加 #home
哈希。要启用默认哈希,您可以使用 /app/view/Application.js
文件中的 defaultToken
配置,该文件可以在您的应用程序中找到
Ext.define('MyApp.Application', {
extend : 'Ext.app.Application',
//...
defaultToken : 'home'
});
当应用程序启动时,它将检查 URI 的当前哈希。如果定义了哈希,它将执行路由处理程序。如果未找到哈希,它将添加 #home
哈希,并且任何路由处理程序都将获得执行以适当处理它。
应用程序还可以在哈希中识别参数。用户 ID 是您可能想要包含在哈希中的参数示例。我们提到了在指南前面使用 #user/1234
作为哈希。在这种情况下,我们可能希望 1234
成为 id 参数。然后,您将设置您的控制器以对 #user/1234
哈希做出反应
Ext.define('MyApp.view.main.MainController', {
extend : 'Ext.app.ViewController',
routes : {
'user/:id' : 'onUser'
},
onUser : function (id) {
//...
}
});
我们使用的路由是 'user/:id'
和冒号 :
。这表示存在一个参数,您的应用程序会将该参数作为参数传递给 onUser 方法。该方法将接收传递给它的相同数量的参数,顺序与路由中指定的顺序相同,这允许轻松包含多个参数。
应用程序可能希望对用户 ID 强制执行特定格式。在到目前为止我们探索的案例中,ID 是数字。您还可以使用路由通过使用 conditions
(条件)配置来等同于对象
Ext.define('MyApp.view.main.MainController', {
extend : 'Ext.app.ViewController',
routes : {
'user/:id' : {
action : 'onUser',
conditions : {
':id' : '([0-9]+)'
}
}
},
onUser : function (id) {
//...
}
});
让我们逐步了解这个示例。首先,'onUser' 方法现在已移动到 action(操作)配置。这与我们将字符串传递给路由时的工作方式类似。然后,我们使用 conditions(条件)配置来提供一个对象。我们要控制的键是带有冒号的参数名称,我们提供一个正则表达式字符串(不是正则表达式对象)。对于 :id
条件,我们使用 ([0-9]+)
,这将允许 0 到 9 之间的数字,长度不限,并将记住匹配项。我们使用字符串,因为正则表达式对象用于匹配整个哈希,因此如果路由中有多个参数,我们需要将正则表达式字符串连接在一起成为单个正则表达式对象。如果您没有为参数提供条件,则它将默认为
([%a-zA-Z0-9\\-\\_\\s,]+)
有时,应用程序可能需要阻止路由的处理。在这种情况下,我们可能想要检查管理权限,以确定是否允许当前用户查看应用程序的一部分。可以将路由配置为使用 before
(之前)操作,该操作可能会停止当前路由、停止所有路由或继续执行路由。
此示例将继续执行路由
Ext.define('MyApp.view.main.MainController', {
extend : 'Ext.app.ViewController',
routes : {
'user/:id' : {
before : 'onBeforeUser',
action : 'onUser'
}
},
onBeforeUser : function (id, action) {
Ext.Ajax.request({
url : '/security/user/' + id,
success : function() {
action.resume();
}
});
},
onUser : function (id) {
//...
}
});
在 onBeforeUser
方法中,:id
参数作为参数传递,但最后一个参数是 action
(操作)。如果您在 action
(操作)上执行 resume
(恢复)方法,路由将继续执行,然后将调用 onUser
方法。请注意,我们可以等待 AJAX 请求完成,然后再继续执行路由。
我们可以通过告诉应用程序通过执行 stop
(停止)方法来停止当前路由执行来扩展此示例
Ext.define('MyApp.view.main.MainController', {
extend : 'Ext.app.ViewController',
routes : {
'user/:id' : {
before : 'onBeforeUser',
action : 'onUser'
}
},
onBeforeUser : function (id, action) {
Ext.Ajax.request({
url : '/security/user/' + id,
success : function () {
action.resume();
},
failure : function () {
action.stop();
}
});
},
onUser : function (id) {
//...
}
});
before
(之前)操作也支持 promise。您可以返回 promise 并 resolve
(解决)或 reject
(拒绝)它,而不是在 action
(操作)参数上执行 resume
(恢复)或 stop
(停止)。在该 promise 解析后,操作将恢复或停止
Ext.define('MyApp.view.main.MainController', {
extend : 'Ext.app.ViewController',
routes : {
'user/:id' : {
before : 'onBeforeUser',
action : 'onUser'
}
},
onBeforeUser : function (id) {
return new Ext.Promise(function (resolve, reject) {
Ext.Ajax.request({
url : '/security/user/' + id,
success : function () {
resolve()
},
failure : function () {
reject();
}
});
});
},
onUser : function (id) {
//...
}
});
注意: 无论您使用 action
(操作)参数还是返回 promise,这都是您的选择。使用任何一种方式,都需要进行解析。action
(操作)参数需要执行其 resume
(恢复)或 stop
(停止)方法,或者 promise 需要解析或拒绝。
如果哈希已更改,但未找到与哈希匹配的路由,则 Router 将不执行任何操作;Router 不会尝试更改哈希,并且会保持未匹配的哈希不变。Router 将在应用程序实例上触发 unmatchedroute
(未匹配路由)事件,该事件可以在 Ext.application
调用中侦听
Ext.application({
name : 'MyApp',
listen : {
controller : {
'#' : {
unmatchedroute : 'onUnmatchedRoute'
}
}
},
onUnmatchedRoute : function (hash) {
//...
}
});
Router 还将触发全局事件
Ext.application({
name : 'MyApp',
listen : {
global : {
unmatchedroute : 'onUnmatchedRoute'
}
},
onUnmatchedRoute : function (hash) {
//...
}
});
也可以直接在 Ext
命名空间上侦听全局事件
Ext.on('unmatchedroute', function (hash) {
//...
});
由于 Ext JS 应用程序可能很复杂,因此有时我们可能需要在单个哈希中使用多个路由。Router 设置为处理此问题,因此在控制器中配置的路由无需额外设置。相反,您可以使用管道符 |
分隔哈希。示例哈希可能是
#user/1234|messages
在这种情况下,我们希望显示 id 为 1234
的用户的用户详细信息,但也显示消息。每个路由将按照哈希指示的顺序执行。然后它们彼此沙箱化。简而言之,如果您停止 user/1234
路由,则 messages
路由将继续执行。重要的是要注意,各个路由的执行顺序与路由在哈希中的顺序相同。对于上面的示例,user/1234
路由将始终在 messages
路由之前执行。
您可以通过更改 Ext.route.Router.multipleToken
属性来修改分隔符。
为了使用多个路由,redirectTo
方法也可以接受对象。这可以使您控制应更新甚至删除完整哈希的哪一部分。假设我们有 3 个不同的路由(它们也可以在不同的控制器中)
routes: {
'bar' : 'onBar',
'baz' : {
action : 'onBaz',
name : 'bazRoute'
},
'foo' : 'onFoo'
}
baz
路由有一个名为 name
的新配置。原因是每个路由现在都已命名,因此我们可以更轻松地引用它。默认情况下,名称是作为 routes
对象中的键传递的 url;bar
和 foo
是其他路由的名称。我们有 bar
、bazRoute
和 foo
作为我们三个路由的名称。
初始哈希可以通过首先传递一个字符串来设置,以使哈希完全是这样
this.redirectTo('foo');
现在哈希将是 #foo
。我们可以通过传递一个字符串来将另一个 token(令牌)添加到该哈希,该字符串使用 multipleToken
属性分隔两个令牌,或者通过传递一个对象
this.redirectTo({
bar : 'bar'
});
现在哈希是 #foo|bar
。让我们检查一下刚刚发生了什么。我们从 #foo
作为我们的哈希开始,并将一个对象传递到 redirectTo
并传递了 bar
键。此键应为我们正在引用的路由的名称,这就是命名概念的关键所在;对于传递的复杂 url,名称是引用它的便捷方式。如果值是 falsy(假值)并且在哈希中找到了命名路由,则将删除它。如果值是 truthy(真值)并且在哈希中找到了命名路由,则哈希的该部分将被新值替换。如果在哈希中未找到命名路由,则将其附加到哈希中。如果我们想替换 foo
路由,我们可以为其传递一个值
this.redirectTo({
foo : 'foober'
});
现在哈希是 #foober|bar
,请注意哈希中各个令牌的顺序已保留。让我们看一个更复杂的例子
this.redirectTo({
bar : 'barber',
bazRoute : 'baz',
foo : null
});
在此示例中,我们删除了一个,更新了另一个,并添加了一个。哈希现在将是 #barber|baz
。通过传递对象,您可以更好地控制哈希将是什么,而无需担心当前哈希是什么,Ext JS 将为您处理它。
如果您的应用程序需要 hashbang 而不是常规哈希,Ext JS 现在可以自动为您处理此问题。Ext.util.History
是处理从浏览器设置和获取哈希的类,Ext JS 可以在其中通过简单的属性自动将哈希设为 hashbang
Ext.util.History.hashbang = true;
现在,它将自动使用 hashbang。您的路由仍然看起来相同
routes : {
'foo' : 'onFoo'
}
并且 redirectTo
方法的使用方式相同
this.redirectTo('foobar');
this.redirectTo({
foo : 'foobar'
});
但是 Ext.util.History
会自动为您将哈希设为 #!foobar
。Router 还可以通过使用应用程序上的新 router
配置为您设置此属性
Ext.application({
name : 'MyApp',
router : {
hashbang : true
}
});
您还可以使用 Router 上的 setter 方法
Ext.route.Router.setHashbang(true);
注意: hashbang 只是一个哈希,只是在 #
之后添加了一个 !
。这意味着您不能混合和匹配哈希和 hashbang,它是二选一的。
如果您需要使 Router 等待某些进程完成,以便不对哈希中的任何更改做出反应,则可以暂停 Router。暂停后,发生的任何哈希更改都将排队,并在恢复后执行。常见的用例是在应用程序启动时延迟路由执行,直到检查 store(数据存储)或用户会话为止。这是一个示例
Ext.application({
name : 'MyApp',
defaultToken : 'home',
launch : function () {
var me = this;
Ext.route.Router.suspend();
me
.checkUserSession()
.then(me.onUser.bind(me), me.onUserError.bind(me));
},
onUser : function (user) {
MyApp.$user = user;
Ext.route.Router.resume();
},
onUserError : function (error) {
// handle error
// do not execute queued hash changes
Ext.route.Router.resume(true);
this.redirectTo('login');
}
});
如果您知道您不想对任何哈希更改进行排队,则 suspend
(暂停)方法可以在为 false
(假)时采用参数
Ext.route.Router.suspend(false);
如果您想在所有已配置的路由之前处理执行的路由,则可以指定通配符路由。这些通配符路由将在其他路由之前执行
routes : {
'*' : 'onRoute',
'foo' : 'onFoo'
}
routes : {
'*' : {
before : 'onBeforeRoute',
action : 'onRoute'
},
'foo' : 'onFoo'
}
通配符路由由传递 *
作为路由的 url 来指示。它的操作将在 foo
路由之前执行。
Ext JS 也公开了一些全局事件。这些事件在 Ext
命名空间上触发,并且可以从 Ext
命名空间或全局事件域监听。以下是这些事件:
beforeroutes
在任何路由执行之前触发。返回 false
允许取消执行路由。beforeroute
在每个路由执行之前触发。返回 false
允许取消执行该特定路由。unmatchedroute
当令牌上没有匹配的路由时触发。如果存在应用程序实例,则也会在该实例上触发。
如前所述,有两种方法可以监听这些事件。更推荐的方式是通过控制器/视图控制器中的全局事件域进行监听。
listen : {
global : {
beforeroutes : 'onBeforeRoutes'
}
},
onBeforeRoutes : function (action, tokens) {
return tokens.length === 1;
}
或者您可以通过 Ext
命名空间进行监听
Ext.on('unmatchedroute', function (token) {
Ext.Msg.alert('Unmatched Route', '"' + token + '" was not matched!');
});
Action
类在 before
action 中,您已经看到了 action
参数。这是 Ext.route.Action
的一个实例,除了恢复或停止 action 之外,还允许更多操作。这个类实际上允许代码更加动态,因为它允许您甚至在执行期间添加 before
和 action
actions。
onBeforeUser : function (id, action) {
return new Ext.Promise(function (resolve, reject) {
action.before(function (id, action) {
action.action(function (id) {
//...
});
action.resume();
});
Ext.Ajax.request({
url : '/security/user/' + id,
success : function () {
resolve()
},
failure : function () {
reject();
}
});
});
}
在这个例子中,我们添加一个新的 before
action,它将被附加到正在执行的 before
actions 数组中(它将最后执行)。在该 before
action 中,我们还添加一个新的 action
action,它将被附加到 action
actions 数组中。请注意,id
参数仍然传递给新的 actions。
如果您想了解 action 何时完全解析或拒绝(所有 before
和 action
actions 都已完成),action
类有一个 then
方法。
onBeforeUser : function (id, action) {
var me = this;
return new Ext.Promise(function (resolve, reject) {
action.then(Ext.bind(me.onFinish, me), Ext.bind(me.onRejection, me));
//...
});
}
如果在任何时候,您想停止 action 类执行其他 before
或 action
actions,action 类有一个 stop
方法可以停止它的执行。
onBeforeUser : function (id, action) {
try {
this.foo();
} catch (e) {
action.stop();
}
}
在 Ext JS 6.5.0 中创建了一个新的 mixin,现在可以在任何类中定义路由。
Ext.define('MyClass', {
mixins : [
'Ext.route.Mixin'
],
routes : {
'foo' : 'onFoo'
},
constructor : function (config) {
this.initConfig(config);
},
doSomething : function () {
this.redirectTo('foo');
},
onFoo : function () {
//...
}
});
这允许不采用 MVC 或 MVVM 架构的应用程序仍然可以使用 Router 功能。