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 模拟用户单击事件
Dec 31 Javascript
在jQuery1.5中使用deferred对象 着放大镜看Promise
Mar 12 Javascript
基于jquery插件制作左右按钮与标题文字图片切换效果
Nov 07 Javascript
60个很实用的jQuery代码开发技巧收集
Dec 15 Javascript
jQuery中offset()方法用法实例
Jan 16 Javascript
javascript实现在网页任意处点左键弹出隐藏菜单的方法
May 13 Javascript
jQuery实现自动滚动到页面顶端的方法
May 22 Javascript
JavaScript 数据类型详解
Mar 13 Javascript
jQuery实现checkbox即点即改批量删除及中间遇到的坑
Nov 11 jQuery
javascript实现Emrips反质数枚举的示例代码
Dec 06 Javascript
利用JavaScript将Excel转换为JSON示例代码
Jun 14 Javascript
浅谈鸿蒙 JavaScript GUI 技术栈
Sep 17 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来自动调用不同服务器上的flash
2006/10/09 PHP
深入解析PHP的Yii框架中的event事件机制
2016/03/17 PHP
PHP网站自动化配置的实现方法(必看)
2017/05/27 PHP
laravel 自定义常量的两种方案
2019/10/14 PHP
PHP实现随机发扑克牌
2020/04/22 PHP
解决ExtJS在chrome或火狐中正常显示在ie中不显示的浏览器兼容问题
2013/01/11 Javascript
jquery实现加载等待效果示例
2013/09/25 Javascript
jQuery实现点击该行即可删除HTML表格行
2014/10/17 Javascript
浅析node连接数据库(express+mysql)
2015/11/30 Javascript
JS跨域解决方案之使用CORS实现跨域
2016/04/14 Javascript
详解照片瀑布流效果(js,jquery分别实现与知识点总结)
2017/01/01 Javascript
微信小程序实战之顶部导航栏(选项卡)(1)
2020/06/19 Javascript
基于jquery实现五星好评
2017/11/18 jQuery
使用vue自定义指令开发表单验证插件validate.js
2019/05/23 Javascript
Vue 实现一个命令式弹窗组件功能
2019/09/25 Javascript
Vue项目打包压缩的实现(让页面更快响应)
2020/03/10 Javascript
addEventListener()和removeEventListener()追加事件和删除追加事件
2020/12/04 Javascript
linux系统使用python获取内存使用信息脚本分享
2014/01/15 Python
浅析Python3爬虫登录模拟
2018/02/07 Python
Python实现按当前日期(年、月、日)创建多级目录的方法
2018/04/26 Python
Python基本数据结构之字典类型dict用法分析
2019/06/08 Python
python中matplotlib实现随鼠标滑动自动标注代码
2020/04/23 Python
Python类class参数self原理解析
2020/11/19 Python
Clarks鞋美国官网:全球领军鞋履品牌
2017/05/13 全球购物
美国最大的农村生活方式零售店:Tractor Supply Company(TSC)
2017/05/15 全球购物
电子信息专业学生自荐信
2013/11/09 职场文书
建筑工程毕业生自我鉴定
2014/01/14 职场文书
公务员职业生涯规划书范文  
2014/01/19 职场文书
我为党旗添光彩演讲稿
2014/09/10 职场文书
幼儿园大班教师个人总结
2015/02/05 职场文书
幼儿园小班个人工作总结
2015/02/12 职场文书
党员年终个人总结
2015/02/14 职场文书
2015年国庆节演讲稿范文
2015/07/30 职场文书
Java用自带的Image IO给图片添加水印
2021/06/15 Java/Android
详解Java线程池是如何重复利用空闲线程的
2021/06/26 Java/Android
Rust中的Struct使用示例详解
2022/08/14 Javascript