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 相关文章推荐
JavaScript打印iframe内容示例代码
Aug 20 Javascript
Jquery实现图片放大镜效果的思路及代码(自写)
Oct 18 Javascript
js,jquery滚动/跳转页面到指定位置的实现思路
Jun 03 Javascript
一个简单的jQuery插件ajaxfileupload.js实现ajax上传文件例子
Jun 26 Javascript
jQuery内容过滤选择器用法分析
Feb 10 Javascript
JS 实现导航菜单中的二级下拉菜单的几种方式
Oct 31 Javascript
js实现开启密码大写提示
Dec 21 Javascript
jquery做个日期选择适用于手机端示例
Jan 10 Javascript
关于jQuery.ajax()的jsonp碰上post详解
Jul 02 jQuery
JS简单获得节点元素的方法示例
Feb 10 Javascript
js获取 gif 的帧数的代码实例
Sep 10 Javascript
Javascript实现贪吃蛇小游戏(含详细注释)
Oct 23 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 分页类 扩展代码
2009/06/11 PHP
php性能优化分析工具XDebug 大型网站调试工具
2011/05/22 PHP
php学习之 循环结构实现代码
2011/06/09 PHP
PHP 实现explort() 功能的详解
2013/06/20 PHP
php实现按文件名搜索文件的远程文件查找器
2014/05/10 PHP
php二维数组合并及去重复的方法
2015/03/04 PHP
JavaScript方法和技巧大全
2006/12/27 Javascript
基于jQuery的简单九宫格实现代码
2012/08/09 Javascript
漂亮的jquery提示效果(仿腾讯弹出层)
2013/02/05 Javascript
完美实现bootstrap分页查询
2015/12/09 Javascript
BootStrap glyphicon图标无法显示的解决方法
2016/09/06 Javascript
JS给swf传参数的实现方法
2016/09/13 Javascript
JavaScript数据结构之二叉查找树的定义与表示方法
2017/04/12 Javascript
Vue单页式应用(Hash模式下)实现微信分享的实例
2017/07/21 Javascript
详解webpack4之splitchunksPlugin代码包分拆
2018/12/04 Javascript
vue分页器组件编写方法详解
2019/06/28 Javascript
解决Antd 里面的select 选择框联动触发的问题
2020/10/24 Javascript
javascript中call,apply,bind的区别详解
2020/12/11 Javascript
Python中的CURL PycURL使用例子
2014/06/01 Python
PyCharm导入python项目并配置虚拟环境的教程详解
2019/10/13 Python
python 两个数据库postgresql对比
2019/10/21 Python
Django 请求Request的具体使用方法
2019/11/11 Python
python+playwright微软自动化工具的使用
2021/02/02 Python
Hawes & Curtis澳大利亚官网:英国经典服饰品牌
2018/10/29 全球购物
时尚圣经:The Fashion Bible
2019/03/03 全球购物
社区志愿者心得体会
2014/01/03 职场文书
魅力教师事迹材料
2014/01/10 职场文书
表扬信格式
2014/01/12 职场文书
骨干教师培训感言
2014/01/16 职场文书
网络技术专业求职信
2014/02/18 职场文书
餐饮周年庆活动方案
2014/08/14 职场文书
党员查摆问题及整改措施
2014/10/10 职场文书
师德标兵事迹材料
2014/12/19 职场文书
保送生自荐信
2015/03/06 职场文书
安全事故隐患排查治理制度
2015/08/05 职场文书
Django如何创作一个简单的最小程序
2021/05/12 Python