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中给animation加更多的运作效果实例
Sep 05 Javascript
jQuery中insertAfter()方法用法实例
Jan 08 Javascript
jquery控制背景音乐开关与自动播放提示音的方法
Feb 06 Javascript
JavaScript中的some()方法使用详解
Jun 09 Javascript
基于JavaScript如何实现ajax调用后台定义的方法
Dec 29 Javascript
谈谈jQuery之Deferred源码剖析
Dec 19 Javascript
jquery表单提交带错误信息提示效果
Mar 09 Javascript
微信小程序实现获取自己所处位置的经纬度坐标功能示例
Nov 30 Javascript
详解如何使用babel进行es6文件的编译
May 29 Javascript
JS使用遮罩实现点击某区域以外时弹窗的弹出与关闭功能示例
Jul 31 Javascript
js实现右键弹出自定义菜单
Sep 08 Javascript
vue 二维码长按保存和复制内容操作
Sep 22 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获取中英混合字符串长度的方法
2014/06/07 PHP
PHP中常用的输出函数总结
2014/09/22 PHP
php中ltrim()、rtrim()与trim()删除字符空格实例
2014/11/25 PHP
php similar_text()函数的定义和用法
2016/05/12 PHP
ThinkPHP5实现作业管理系统中处理学生未交作业与已交作业信息的方法
2016/11/12 PHP
php获取开始与结束日期之间所有日期的方法
2016/11/29 PHP
javascript函数库-集合框架
2007/04/27 Javascript
JavaScript 创建对象
2009/07/17 Javascript
javascript使用onclick事件改变选中行的颜色
2013/12/30 Javascript
js常用数组操作方法简明总结
2014/06/20 Javascript
解决jQuery ajax请求在IE6中莫名中断的问题
2016/06/20 Javascript
JS HTML5拖拽上传图片预览
2016/07/18 Javascript
Vue实现选择城市功能
2017/05/27 Javascript
jquery网页加载进度条的实现
2017/06/01 jQuery
让nodeJS支持ES6的词法----babel的安装和使用方法
2017/07/31 NodeJs
AngularJs每天学习之总体介绍
2017/08/07 Javascript
详解Angular操作cookies方法
2018/06/01 Javascript
详解vuex的简单todolist例子
2019/07/14 Javascript
angular共享依赖的解决方案分享
2020/10/15 Javascript
[49:05]OG vs Newbee 2019DOTA2国际邀请赛淘汰赛 胜者组 BO3 第二场 8.21.mp4
2020/07/19 DOTA
[43:58]DOTA2-DPC中国联赛定级赛 LBZS vs SAG BO3第一场 1月8日
2021/03/11 DOTA
Python中使用装饰器和元编程实现结构体类实例
2015/01/28 Python
用map函数来完成Python并行任务的简单示例
2015/04/02 Python
Python实现学校管理系统
2018/01/11 Python
Python简单实现查找一个字符串中最长不重复子串的方法
2018/03/26 Python
对pandas通过索引提取dataframe的行方法详解
2019/02/01 Python
自适应线性神经网络Adaline的python实现详解
2019/09/30 Python
如何使用Python发送HTML格式的邮件
2020/02/11 Python
Python 获取异常(Exception)信息的几种方法
2020/12/29 Python
Charlotte Tilbury美国官网:英国美妆品牌
2017/10/13 全球购物
教师师德承诺书
2014/03/26 职场文书
《春雨》教学反思
2014/04/24 职场文书
综艺节目策划方案
2014/06/13 职场文书
乡镇镇长个人整改措施
2014/10/01 职场文书
python获取淘宝服务器时间的代码示例
2021/04/22 Python
Java面试题冲刺第十九天--数据库(4)
2021/08/07 Java/Android