什么是 ui-router
不同于 ng-router 基于 url 的路由系统, ui-router 提供了一个基于 state 状态机的路由方式。它可以实现在不改变 url 情况下更新视图中局部内容,也可以在一个页面内嵌套并更新多个视图(状态的嵌套,这是相对于 ng-router 的一大优势),使用 ui-router 可以轻松应对复杂场景的页面应用。
ui-router 基本用法
state 方法会返回 $stateProvider 本身,和 ng-router 一样支持链式操作。
抽象 state
1 2 3 4 5 6 7
| $stateProvider .state('tabs', { url: '/tab', abstract: true, templateUrl: 'templates/tabs.html' })
|
上述代码描述了一个抽象的状态,一个抽象的状态可以有子状态但不能显式激活,它将被隐性激活当其子状态被激活时。
下面是一些你将可能会使用到抽象状态的示例:
- 为所有子状态预提供一个基url在父状态中设置template属性,子状态对应的模板将插入到父状态模板中的ui-view(s)中
- 通过resolve属性,为所有子状态提供解决依赖项通过data属性,为所有子状态或者事件监听函数提供自定义数据
- 运行onEnter或onExit函数,这些函数可能在以某种方式修改应用程序。
- 上面场景的任意组合
请记住:抽象的状态模板仍然需要,来让自己的子状态模板插入其中。因此,如果您使用抽象状态只是为了预提供基url、提供解决依赖项或者自定义data、运行onEnter/Exit函数,你任然需要设置template: ““。
上述代码中为所有子状态指定了一个基 url ,后续所有的子状态都会继承这个 url (表现形式是:/tab/childUrl
)。
子 state
1 2 3 4 5 6 7 8 9
| .state('tabs.questionList', { url: '/questionList', views: { 'questionList': { templateUrl: 'templates/Question/questionList.html', controller: 'QuestionController' } } })
|
使用点语法为 tabs
状态创建了一个子状态,对应的 html 代码应该是这样的:
1 2 3
| <ion-tab icon="ion-navicon" href="#/tab/questionList"> <ion-nav-view name="questionList"></ion-nav-view> </ion-tab>
|
ion-nav-view
实际上它是一个具有 ui-view
指令的 html 标签。 name
是 ui-view
的名字,tabs 状态对应的是包含了 questionList 视图的 tabs.html,questionList 嵌套在 tabs 页面内部,所以 questionList 是 tabs 的子状态。
views
中的 questionList
是视图的名称,ui-router 将会把这个视图替换成 templateUrl
中对应的 html。
controller
是 questionList
视图对应的控制器。
views
一个 url 对应的页面中嵌套有多个视图的时候,可以再 views 对象中添加对应的视图名字为 key 的对象,运行时嵌套的视图会按照规则被自动替换。
1 2 3 4 5 6 7 8 9 10 11 12 13
| .state('tabs.mainPage', { url: '/questionList', views: { 'questionList': { templateUrl: 'templates/Question/questionList.html', controller: 'QuestionController' }, 'answerList': { templateUrl: 'templates/Answer/answerList.html', controller: 'AnswerController' } } })
|
对应的 html :
1 2
| <div ui-view="questionList"></div> <div ui-view="answerList"></div>
|
resolve
为子状态注入依赖,参见:http://bubkoo.com/2014/01/01/angular/ui-router/guide/nested-states%20&%20nested-views/#继承解决的依赖项
页面跳转
页面跳转可以使用 $state.go(stateName [,paramObject] [,option])
第三个参数一般不使用,具体 api 参考请见
https://angular-ui.github.io/ui-router/site/#/api/ui.router.state.$state#methods_go
例子:
1 2 3 4
| $state.go('tabs.discovery', { anId: anId });//去到绝对state路径 $state.go('^.discovery', { anId: anId });//去姊妹状态 $state.go('^');//回父状态 $state.go('.child.grandchild');//去孙状态
|
或者可以使用 ui-sref
指令在 html 中直接写 state 跳转。
1 2 3
| <li ui-sref-active="current"><a ui-sref="home.index">1</a></li> <li ui-sref-active="current"><a ui-sref="home.project">2</a></li> <li ui-sref-active="current"><a ui-sref="^.project.home({id:3})">3</a></li>
|
ui-sref-active
指令将在元素被选中的时候,为元素添加 active
的 class。
实战
tab 单页面应用
对于一个拥有两个 tab 的单页面应用来说,每一个 tab 都对应着一个自己的视图,每一个 tab 都应该拥有一个自己的导航栈。但对于 ui-router 而言,我们始终是在替换同一个视图的内容,所以所有的页面都要挂在 tab 的子级,而不是更下方的层次。
公共页面的处理
从不同 tab 中的页面跳转至相同页面情况存在时,需要将公共页面作为 tab 的子 state,分别在需要跳转的 tab 下使用不同的名称挂载,url 也需要不同,类似如下代码:
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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| // 问题列表state .state('tabs.questionList', { url: '/questionList', views: { 'questionList': { templateUrl: 'templates/Question/questionList.html', controller: 'QuestionController' } } }) // 问题详情 .state('tabs.questionList-question-detail', { url: '/questionList/question/:quId', views: { 'questionList': { templateUrl: 'templates/Public/question-detail.html', controller: 'QuestionDetailCtrl' } } }) // 答案详情 .state('tabs.questionList-answer-detail', { url: '/questionList/answer/:anId', views: { questionList: { templateUrl: 'templates/Public/answer-detail.html', controller: 'AnswerDetailController' } } }) //发现 .state('tabs.discovery', { url: '/discovery', views: { 'discovery': { templateUrl: 'templates/Discovery/discovery.html', controller: 'DiscoveryController' } } }) .state('tabs.discovery-question-detail',{ url:'/discovery/question/:quId', views: { 'discovery': { templateUrl: 'templates/Public/question-detail.html', controller: 'QuestionDetailCtrl' } } }) .state('tabs.discovery-answer-detail',{ url:'/discovery/answer/:anId', views: { 'discovery': { templateUrl: 'templates/Public/answer-detail.html', controller: 'AnswerDetailController' } } })
|
这里的页面逻辑是,问题列表->问题详情->答案详情&发现->问题详情|发现->答案详情
。我们就需要按照如上方式进行 state 的配置。