在Angular2中使用UI-Router--入门篇
1. UI-Router概述
UI-Router为客户端的页面应用提供了非常灵活的,基于状态的路由机制。在此介绍UI-Router基于angular2框架的使用,需要有angular2基础知识和npm/node使用经验。
2. UI-Router开发指南
1) 安装
· 通过npm安装
npm install --save @uirouter/angular
· 通过CDN引用
<script src="//unpkg.com/@uirouter/angular/_bundles/ui-router-ng2.js"></script>
2) 快速使用
· 定义宿主组件及视图入口(viewport)
/** Viewport Components */
@Component({
selector:'my-app',
template:`
<a uiSref="hello"uiSrefActive="active">Hello</a>
<auiSref="about"uiSrefActive="active">About</a>
<ui-view></ui-view>
`
})
export classApp{}
· 定义状态(state)
/** States */
let helloState={name:'hello',url:'/hello', component:Hello};
let aboutState={name:'about',url:'/about', component:About};
· 定义module并注册状态
/** Root Application NgModule */
@NgModule({
imports:[
BrowserModule,
UIRouterModule.forRoot({states: [ helloState, aboutState ] })
],
declarations:[App,Hello,About],
bootstrap:[App]
})
class RootAppModule{}
· 启动module
/** Angular2 bootstrap */
platformBrowserDynamic().bootstrapModule(RootAppModule);
3) 属性解析
· 模板属性
/** Viewport Components */
Viewport:宿主组件上会有 <ui-view>标签作为视图入口,将由被激活的状态所对应的组件填充。
Links: 链接标签含有uiSref属性,作用类似超链接的href属性,不同在于href链接至一个url,而uiSref链接至一个状态。当用户点击链接,对应的状态将被激活,uiSref指令会基于对应状态的url为你创建href链接属性。
Active Link:uiSref链接还含有一个指令: uiSrefActive='active',添加该指令会在目标状态激活时,为链接添加触发时的样式。
· 状态属性
/** States */
name:状态名。
url:当状态被激活时,浏览器所显示的url。
component: 定义了当状态被激活时,用来替换显示在视图口的组件类。
· 路由配置
/** Root Application NgModule */
imports:[ BrowserModule, UIRouterModule.forRoot({ ...})] : UIRouterModule.forRoot方法创建了UI-Router module,同时注册了所需状态。
在状态路由启动之前,我们可以设定一些必要配置,并将这些配置作为对象传入forRoot()方法。其中config配置的值可以是一个函数。
imports: [
...
UIRouterModule.forRoot({
states:INITIAL_STATES,
useHash:true,
config:uiRouterConfigFn
})
]
/** config函数配置同样适用于forChild()懒加载方法*/
· Resolve数据属性
当路由被激活或进行切换时需要获取依赖数据,我们可以在定义状态时,通过resolve属性获取所需数据。如果状态包含resolve属性,当其被UI-Router激活,初始化对应组件前,会先获取resolve内定义的依赖数据并将其赋给组件。
状态内的resolve属性值是数组类型,数组内每一项是一个元数据对象。其中:
token: 可以理解是依赖注入的标识,用以注入获取的数据。
deps: 定义获取数据时,获取方法(resolveFn )所需的依赖。定义的顺序与注入获取方法(resolveFn )内的参数需一一对应。
resolveFn:定义一个获取的方法,注入deps内定义的依赖,获取目标数据并返回为promise类型。
resolve: [
{
token:'people',
deps:[PeopleService],
resolveFn:(peopleSvc)=>peopleSvc.getAllPeople()
}
]
直到promise成功获取到resolves数据,UI-Router才会初始化显示的 component,获取的数据通过@input装饰器函数赋给组件:
export classPeople{
@Input()people;
}
· 传递状态参数
当需要向状态传递参数时以进行具体数据获取时,只需在定义时在参数前添加冒号定义,在参数前可以如下定义:
export constpersonState={
name:'person',
url:'/people/:personId',
component:Person,
resolve:[
{
token:'person',
deps:[Transition,PeopleService],
resolveFn:(trans,peopleSvc)=>peopleSvc.getPerson(trans.params().personId)
}
]
}
/** 当本例状态激活时,浏览器路径也会对应如:/people/21*/
当创建链接去激活一个带有参数的状态时,可通过[uiParams]指令添加参数,示例如下:
<li *ngFor="let person ofpeople">
<a uiSref="person"[uiParams]="{ personId: person.id }">
{{person.name}}
</a>
</li>
· 嵌套状态
所有的状态将成树扎状,顶层是唯一的匿名根状态,其它状态可互为兄弟状态或父子状态,即嵌套状态。外层状态可视为父状态,内层则为子状态。子状态只需定义时,将状态名拼接至福状态名之后,由“.”连接,即“父状态名.子状态名”,同时url声明无需父状态部分:
export constpersonState={
name:'people.person',
url:'/:personId',
component:Person,
resolve:[
{
token:'person',
deps:[Transition,PeopleService],
resolveFn:(trans,people)=>
people.find(person=>person.id===trans.params().personId)
}
]
};
注:此处resolve获取数据,注入依赖时将会注入父状态解析后的结果数据。
当需要在父状态对应的显示组件内,链接到子状态时,链接指令对应状态名变更为:
<a uiSref="people.person"[uiParams]="{ personId: person.id }">
或相对路径形式:
<a uiSref=".person"[uiParams]="{ personId: person.id }">
3. UI-Router进阶
1) Views
当某一状态被激活时,与其对应的视图组件会被渲染填充到对应的视图入口,通常我们使用component属性在指定对应的视图组件,如:
var state={
name:'home',
component:HomeComponent
}
但是当我们在同一状态下,需要在页面不同区域渲染不同的视图组件时, 我们需要在定义状态时借助新的属性views来使用命名视图,示例如下:
var mainState={
name:'main',
views:{
header:HeaderComponent,
nav:NavComponent,
content:MainComponent,
}
}
为views属性赋值为一个,列出目标视图入口的名称,及其对应显示组件的键值对对象。目标视图入口需要通过name=”xx”属性指定命名:
var child={
name:'parent.child',
views:{
//targets uiview name='nav' created by ParentComponent
'nav': NavComponent,
//targets uiview name='header' created by ParentComponent
'header':HeaderComponent,
}
}
2) 过渡
UI-Router的运行类似一个状态机,不同的页面显示对应不同的状态,而状态之前的切换过程我们称之为过渡。
· 不同的过渡及其访问
From state/to state:我们由一个A状态进入另一个B状态,A状态为’from’状态,B则为’to’状态,UI-Router提供了一个Transition对象来表示一次过渡,可以通过Transition对象的Transition.to() 和Transition.from()方法分别访问’from’状态和’to’状态。
Exiting and entering:由一个A状态进入另一个B状态,在此期间我们离开(exited)了A状态,进入(entered)了B状态。可以通过Transition.entering() 和Transition.exiting()方法分别访问进入和离开的状态。
Param value changes: 当状态保持不变,状态参数发生变化,实际上是离开了并重新进入了该状态,可通过Transition.params('to') 和 Transition.params('from')方法分别访问新旧参数。
Nested states:当访问嵌套状态时,通过父状态访问子状态,子状态成为目标激活状态,父状态不会被离开,成为保留状态,通过 Transition.retained()访问。
· 过渡的生命周期
一次过渡可能会涉及获取数据等操作,因此过渡存在以下几个生命周期:
Create: 代表一个过渡被创建
Before:代表一个过渡开始前
Start: 代表一个过渡已经触发
Retain:某状态被保留
Enter:进入某状态
Finish:过渡即将结束
Success /Error: 代表过渡已结束,或是成功或是失败