Angular2学习笔记——详解路由器模型(Router)


Posted in Javascript onDecember 02, 2016

Angular2以组件化的视角来看待web应用,使用Angular2开发的web应用,就是一棵组件树。组件大致分为两类:一类是如list、table这种通放之四海而皆准的通用组件,一类是专为业务开发的业务组件。实际开发中大部分时间我们都需要处理业务组件。对于SPA应用来说,一个通用的问题就是如何控制页面的切换,解决这个问题的通用方法就是利用路由器来实现。

路由配置

现在我们先撇开Angular2来看看通用的路由器模型。通常来讲SPA应用需要路由配置信息:

[
 { path: '', pathMatch: 'full', redirectTo: '/inbox' },
 {
  path: ':folder',
  children: [
   {
    path: '',
    component: ConversationsCmp
   },
   {
    path: ':id',
    component: ConversationCmp,
    children: [
     { path: 'messages', component: MessagesCmp },
     { path: 'messages/:id', component: MessageCmp }
    ]
   }
  ]
 },
 {
  path: 'compose',
  component: ComposeCmp,
  outlet: 'popup'
 },
 {
  path: 'message/:id',
  component: PopupMessageCmp,
  outlet: 'popup'
 }
]

这个配置信息定义了应用的潜在路由状态(Router State)。一个路由状态代表了一份组件布置信息。 现在我们换一个视角来看这份配置:

Angular2学习笔记——详解路由器模型(Router)

在这棵配置树中,每一个节点就是一个路由,它对应了一个组件。

路由状态

在路由树这种视角下,每一个路由状态就是配置树的一棵子树。下图中的路由状态下,最终被激活的组件是ConversationCmp:

Angular2学习笔记——详解路由器模型(Router)

导航

路由器的首要任务就是控制在不同路由状态之间导航以及更新组件树。如下图所示,当我们导航到另一个页面时,路由状态也会发生改变,随之页面上显示的组件也跟随变化。

Angular2学习笔记——详解路由器模型(Router)

到此为止路由器的基本模型已经介绍完毕,下面我们来看一下Angular2中的路由模型。

Angular2路由处理流程

Angular2学习笔记——详解路由器模型(Router)

Angular2对待一个URL的处理流程为:

1.应用重定向

2.识别路由状态

3.应用哨兵与传递数据

4.激活对应组件

重定向

Angular2学习笔记——详解路由器模型(Router)

假设我们访问的地址是:http://hostname/inbox/33/message/44。路由器首先根据配置规则:

{ path: ‘', pathMatch: ‘full', redirectTo: ‘/inbox' }

来判断是否需要重定向,如果我们的url是http://hostname/此时,就是重定向到http://hostname/inbox,根据配置规则:folder,这时候被激活的组件就是ConversationComp。但现在我们的url是http://hostname/inbox/33/message/44,所以不会发生重定向。

识别路由状态

Angular2学习笔记——详解路由器模型(Router)

接下来路由器会为这个URL分发一个路由状态。根据配置规则

{
  path: ':folder',
  children: [
   {
    path: '',
    component: ConversationsCmp
   },
   {
    path: ':id',
    component: ConversationCmp,
    children: [
     { path: 'messages', component: MessagesCmp },
     { path: 'messages/:id', component: MessageCmp }
    ]
   }
  ]
 }

/inbox/33/message/44首先匹配:folder,对应组件为ConversationCmp,而后进入子配置,'message/:id',MessageCmp组件被激活。

Angular2学习笔记——详解路由器模型(Router)

根据上图的状态树,我们可以看出MessageCmp与ConversationCmp对应的路由状态。与此同时一个被称为激活路由(ActivatedRoute)的对象将被创建,并可以在MessageCmp访问到,通过ActivatedRoute我们可以拿到它的routerState属性,通过路由状态我们可以拿到具体参数如id对应的44。从此也可以看出拿到父级参数id(33)就必须访问父级的路由状态。

ngOnInit() {
    this.sub = this.router.routerState.parent(this.route).params.subscribe(params => {
      this.parentRouteId = +params["id"];
    });
  }

哨兵与分发数据

Angular2学习笔记——详解路由器模型(Router)

哨兵的作用是判断是否允许应用在不同状态间进行切换,比如:如果用户没有登陆就不允许进入Message页面。哨兵可以用来判断是否允许进入本路由状态,是否允许离开本路由状态。下例中的CanActivate用来判断是否允许进入,这个服务类需要继承CanActivate接口。

import { AuthGuard }        from '../auth-guard.service';

const adminRoutes: Routes = [
 {
  path: 'admin',
  component: AdminComponent,
  canActivate: [AuthGuard],
  children: [
   {
    path: '',
    children: [
     { path: 'crises', component: ManageCrisesComponent },
     { path: 'heroes', component: ManageHeroesComponent },
     { path: '', component: AdminDashboardComponent }
    ],
   }
  ]
 }
];

export const adminRouting: ModuleWithProviders = RouterModule.forChild(adminRoutes);
import { Injectable }   from '@angular/core';
import { CanActivate }  from '@angular/router';

@Injectable()
export class AuthGuard implements CanActivate {
 canActivate() {
  console.log('AuthGuard#canActivate called');
  return true;
 }
}

哨兵内容涉及到另一个部分知识,所以我会把他放到下一篇文章中。

Angular2的路由器允许我们在进入组件中拿到除当前路由参数之外的其他信息。在路由配置中使用resolve属性指定一个数据分发器。

[
 {
  path: ':folder',
  children: [
   {
    path: '',
    component: ConversationsCmp,
    resolve: {
     conversations: ConversationsResolver
    }
   }
  ]
 }
]

数据分发器需要继承DataResolver接口:

@Injectable()
class ConversationsResolver implements DataResolver {
 constructor(private repo: ConversationsRepo, private currentUser: User) {}

 resolve(route: ActivatedRouteSnapshot, state: RouteStateSnapshot):
   Promise<Conversation[]> {
  return this.repo.fetchAll(route.params['folder'], this.currentUser);
 }
}

还需要把这个数据分发器加入到module的Providers中:

@NgModule({
 //...
 providers: [ConversationsResolver],
 bootstrap: [MailAppCmp]
})
class MailModule {
}

platformBrowserDynamic().bootstrapModule(MailModule);

而后我们在组件中就可以通过ActivatedRoute来访问分发数据了。

@Component({
 template: `
  <conversation *ngFor="let c of conversations | async"></conversation>
 `
})
class ConversationsCmp {
 conversations: Observable<Conversation[]>;
 constructor(route: ActivatedRoute) {
  this.conversations = route.data.pluck('conversations');
 }
}

激活组件

Angular2学习笔记——详解路由器模型(Router)

此时路由器根据路由状态来实例化组件并把他们放到合适的路由组出发点上。

@Component({
 template: `
  ...
  <router-outlet></router-outlet>
  ...
  <router-outlet name="popup"></router-outlet>
 `
})
class MailAppCmp {
}

如‘/inbox/33/message/44(popup:compose)',首先实例化ConversationCmp放到主<router-outlet>中,然后实例化MessageCmp放到name为popup的<Router-outlet>中。

现在路由器对URL的解析过程完毕。但是如果用户想从MessageCmp中跳转到别的路由状态该如何做呢?Angular2提供了两种方式。

一种是通过router.navigate方法来导航:

@Component({...})
class MessageCmp {
 private id: string;
 constructor(private route: ActivatedRoute, private router: Router) {
  route.params.subscribe(_ => this.id = _.id);
 }

 openPopup(e) {
  this.router.navigate([{outlets: {popup: ['message', this.id]}}]).then(_ => {
   // navigation is done
  });
 }
}

一种是利用router-link方式:

@Component({
 template: `
  <a [routerLink]="['/', {outlets: {popup: ['message', this.id]}}]">Edit</a>
 `
})
class MessageCmp {
 private id: string;
 constructor(private route: ActivatedRoute) {
  route.params.subscribe(_ => this.id = _.id);
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jQuery 常见学习网站与参考书
Nov 09 Javascript
深入理解JavaScript系列(3) 全面解析Module模式
Jan 15 Javascript
基于jQuery选择器的整理集合
Apr 26 Javascript
js综合应用实例简单的表格统计
Sep 03 Javascript
jquery中的过滤操作详细解析
Dec 02 Javascript
JavaScript对表格或元素按文本,数字或日期排序的方法
May 26 Javascript
浅谈关于JavaScript API设计的一些建议和准则
Jun 24 Javascript
EasyUI在表单提交之前进行验证的实例代码
Jun 24 Javascript
Node.js如何自动审核团队的代码
Jul 20 Javascript
vue分页组件table-pagebar使用实例解析
Nov 15 Javascript
Vue中$refs的用法详解
Jun 24 Javascript
微信小程序缓存过期时间的使用详情
May 12 Javascript
基于jQuery实现的幻灯图片切换
Dec 02 #Javascript
JavaScript中清空数组的方法总结
Dec 02 #Javascript
浅谈js中几种实用的跨域方法原理详解
Dec 02 #Javascript
基于JQuery实现的跑马灯效果(文字无缝向上翻动)
Dec 02 #Javascript
探讨跨域请求资源的几种方式(总结)
Dec 02 #Javascript
jQuery实现倒计时(倒计时年月日可自己输入)
Dec 02 #Javascript
JavaScript 计算笛卡尔积实例详解
Dec 02 #Javascript
You might like
PHP VS ASP
2006/10/09 PHP
PHP的RSA加密解密方法以及开发接口使用
2018/02/11 PHP
PHP后台实现微信小程序登录
2018/08/03 PHP
jquery $(document).ready() 与window.onload的区别
2009/12/28 Javascript
jquery选择器之层级过滤选择器详解
2014/01/27 Javascript
js检测网络是否具体连接功能的代码
2014/05/23 Javascript
批量修改标签css样式以input标签为例
2014/07/31 Javascript
JS实现清除指定cookies的方法
2014/09/20 Javascript
javascript实现修改微信分享的标题内容等
2014/12/11 Javascript
JS中改变this指向的方法(call和apply、bind)
2016/03/26 Javascript
jQuery中on绑定事件后引发的事件冒泡问题如何解决
2016/05/25 Javascript
jQuery.form.js的使用详解
2017/06/14 jQuery
收藏AngularJS中最重要的核心功能
2017/07/09 Javascript
AngularJS使用ng-repeat遍历二维数组元素的方法详解
2017/11/11 Javascript
mongodb初始化并使用node.js实现mongodb操作封装方法
2019/04/02 Javascript
微信小程序实现图片选择并预览功能
2019/07/25 Javascript
vue-router跳转时打开新页面的两种方法
2019/07/29 Javascript
vue-resource:jsonp请求百度搜索的接口示例
2019/11/09 Javascript
angular中的post请求处理示例详解
2020/06/30 Javascript
Python 不同对象比较大小示例探讨
2014/08/21 Python
基于python3实现socket文件传输和校验
2018/07/28 Python
python中实现控制小数点位数的方法
2019/01/24 Python
TensorFlow实现简单的CNN的方法
2019/07/18 Python
详解Python3 pickle模块用法
2019/09/16 Python
Python面向对象魔法方法和单例模块代码实例
2020/03/25 Python
Django 解决由save方法引发的错误
2020/05/21 Python
termux中matplotlib无法显示中文问题的解决方法
2021/01/11 Python
墨尔本最受欢迎的复古风格品牌:Princess Highway
2018/12/21 全球购物
NFL加拿大官方网上商店:NHLShop.ca
2019/03/12 全球购物
波兰珠宝品牌:YES
2019/08/09 全球购物
办公室年终个人自我评价
2013/10/28 职场文书
《乌塔》教学反思
2014/02/17 职场文书
工商治理实习生的自我评价分享
2014/02/20 职场文书
2014年高校辅导员工作总结
2014/12/09 职场文书
婚庆答谢词
2015/01/04 职场文书
遗嘱格式范本
2015/08/07 职场文书