用路由控制程序
在一个正常的网站,用户导航到不同的页面是通过点击链接或填写表单,当然,在一个单页程序,用户不需要下载新页面,在单页面和组件里处理反应,那么你怎么让用户使用浏览器的前进”和“后退”按钮?答案是Ext JS 5新的路由功能的URL散列。
路由有什么用
路由被浏览器作为历史记录轨迹记录程序轨迹状态,路由还允许深度链接到应用程序可以直接链接到一个特定的应用程序的一部分。
路由不能用于什么
路由不能记录数据和会话,数据应该存储在一个如 cookie 或 localstorage 的持久数据源,路由只是一种手段,跟踪应用程序的状态。
散列是什么
互联网上的浏览器导航用URI连接各个部分,看一个简单的URI:
1
|
http:
//www.example.com/apps/users#user/1234
|
相对很熟悉吧,你可能不认识
#user=1234
,这部分就是URI的“散列”或者片段标识符。更多散列的知识,看这里
http://en.wikipedia.org/wiki/Fragment_identifier。散列为程序提供了一个方法控制历史轨迹让浏览器不用重新加载页面。随着散列的变化,浏览器保留整个URI历史堆栈,然后允许你使用浏览器的前进/后退按钮来遍历URI包括可能会改变的散列值。例如,如果你更新散列:
1
|
http:
//www.example.com/apps/users#user/5678
|
在程序内可以利用浏览器触发的
hashchange
事件。
用户可以点击后退按钮返回到
#user=1234
散列,这些改变反应到程序里,重要的是散列没有发送到服务器,散列通常是在客户端URL解释处理。Ext路由器依赖于浏览器的哈希(散列)功能允许应用程序状态跟踪和深度链接。
在程序里实现路由
路由类是Ext JS 5一个新成员,建立了散列变化解释很简单的MVC应用程序,一直有Ext.util.History,你可以使用散列的变化作出反应。Ext.util.History提供了更多的手动过程和一个合适的类需要路由。在Ext JS 5 MVC程序里提供了一个简单集成路由主应运,在视图控制器里定义路由。路由是一个字符串匹配散列深度链接到程序里,这是一个基本的例子控制器实现路由 :
1
2
3
4
5
6
7
8
9
10
11
|
Ext.define(
'MyApp.view.main.MainController'
, {
extend :
'Ext.app.ViewController'
,
routes : {
'users'
:
'onUsers'
},
onUsers : function() {
//...
}
});
|
这条路由反应到
#users
散列并执行控制器实例里的
onUsers
方法,像你看到的,
routes
配置是根层里的
config
对象实例。
更新散列
要更新散列,控制器有个redirectTo方法:
1
|
this
.redirectTo(
'user/1234'
);
|
这交将更新散列到
"#user/1234"
且任何路由识别到这个路由都将执行,也许有些时候当前试图更新散列是一样的散列,这样,
redirectTo
将返回
false
且散列不更新不会收到任何配置路由,redirectTo还接受第二个参数强制路由这个散列通过
true
的反应。
1
|
this
.redirectTo(
'user/1234'
,
true
);
|
即使当前散列哈希被传递给匹配的
redirectTo
,路由仍将执行任何匹配的路线。
默认令牌
当程序开始,如果没有提供一个散列它可以添加一个默认散列,例如,如果使用一个
#home
散列程序显示一个指示板,如果没有其他散列存在时你可能想添加
#home
散列到URL,开启默认散列,可以用
defaultToken
在
/app/view/Application.js
文件,在你的程序里找:
1
2
3
4
5
6
7
|
Ext.define(
'MyApp.Application'
, {
extend :
'Ext.app.Application'
,
//...
defaultToken :
'home'
});
|
当程序运行,将检查URL当前的散列,如果有定义,交给路由处理,如果没有找到,将添加
#home
散列且所有路由都会收到并适当处理。
散列与参数
程序可以识别散列里的参数,一个用户的ID就是一个参数的例子,你可能想包含在散列里。我们在早些时候的教程提到过
#user/1234
一样的散列,这样,我们可以得到1234这个ID参数,您将设置控制器对
#user/1234
散列:
1
2
3
4
5
6
7
8
9
10
11
|
Ext.define(
'MyApp.view.main.MainController'
, {
extend :
'Ext.app.ViewController'
,
routes : {
'user/:id'
:
'onUser'
},
onUser : function(id) {
//...
}
});
|
路由我们用
'user/:id'
和分隔':'。这表示是一个参数并且程序将传递这个参数到onUser方法就像是它的属性。方法将获得相同数量的参数传递给它在同一订单中指定的路由,它允许简单的包含多个参数。
散列参数格式化
程序可能想执行特定格式的用户ID,到目前为止我们只搜索ID为数字,你也可以使用路由等同于一个对象通过使用条件(
conditions
)配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
Ext.define(
'MyApp.view.main.MainController'
, {
extend :
'Ext.app.ViewController'
,
routes : {
'user/:id'
: {
action :
'onUser'
,
conditions : {
':id'
:
'([0-9]+)'
}
}
},
onUser : function(id) {
//...
}
});
|
让我们来看看这个例子,首先,‘onUser’方法移到action配置,这类似我们传递字符串到路由,这时用条件配置提供一个对象,关键是控制分隔后的参数名提供一个正则表达式字符串(不是正则表达式对象),用
:id
条件,我们用
([0-9]+)
,允许匹配0到9之间任何长度的数字。用字符串是因为正则表达式匹配整个散列,所以如果路由有多个参数需要把正则表达式字符串连接在一起变成单个正则表达式对象。如果不提供连接参,它默认是:
1
|
([%a-zA-Z0-9\\-\\_\\s,]+)
|
处理路由
有时可能是应用程序需要预防的处理路线,在这种情况下,我们能想确认当前用户是否允许访问程序这部分视图,路由在激活前配置,可以终止当前路由,所有路由或继续执行的路由。
这个例子将继续执行的路由:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
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请求完成之后路由继续执行。(原文是:Notice that we can wait for an AJAX request to complete before we need to continue the route execution. ----按代码理解好像不对?!)
我们扩展这个例子告诉程序停止执行当前路由,用
stop
方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
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) {
//...
}
});
|
Ext JS程序可能很复杂且可能有很多控制器设置侦听同样的路由,然而,只有一个控制器设置在激活之前只有一个ajax请求,如果我们传递
true
到
action
属性的
stop
方法,我们可以停止所有队列路由执行,不只是处理当前路由:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
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(
true
);
}
});
},
onUser : function(id) {
//...
}
});
|
现在,ajax返回错误,传递
true
在所有控制器里取消路由所有的处理。
注意:如果你没有执行
resume
或者 stop
,路由不中断永远正确完成,执行方法是很重要的。
处理默认路由
如果散列改变但没有路由这将匹配默认路由,路由什么也不做;路由不尝试改变散列且使用默认散列,路由将在程序里触发
unmatchedroute
事件在
Ext.application
里侦听调用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
Ext.application({
name :
'MyApp'
,
listen : {
controller : {
'#'
: {
unmatchedroute :
'onUnmatchedRoute'
}
}
},
onUnmatchedRoute : function(hash) {
//...
}
});
|
单散列用在多路由
一旦Ext JS程序编译,有时我们会在单个散列使用多个路由,不用额外在控制器里设置路由就可以处理这些,相反,你可以用散列的竖线:|。这有例子:
1
|
`#user/1234|messages`
|
这样,我们可以显示ID为1234的用户的细节,也可以显示信息。每个路由将由散列的顺序执行,它们在沙箱里一个接一个执行。这个例子,如果你停止
user/1234
路由,
messages
路由继续执行,重要的是要注意个人的执行顺序路由,路由的顺序是相同的散列。
user/1234
路由一直在
messages
路由前执行在上面的例子。
你可以修改分隔符,通过改变
Ext.app.route.Router.multipleToken
属性。