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的防止大图片撑破页面的实现代码(立即缩放)
Oct 24 Javascript
由Javascript实现的页面日历
Nov 04 Javascript
js读取注册表的键值示例
Sep 25 Javascript
javascript实现继承的简单实例
Jul 26 Javascript
js实现的二级横向菜单条实例
Aug 22 Javascript
JavaScript 继承详解(五)
Oct 11 Javascript
Vue.js原理分析之observer模块详解
Feb 17 Javascript
jQuery zTree树插件的使用教程
Aug 16 jQuery
Vue filter 过滤当前时间 实现实时更新效果
Dec 20 Javascript
JavaScript实现PC端横向轮播图
Feb 07 Javascript
解决vue+webpack项目接口跨域出现的问题
Aug 10 Javascript
Webpack的Loader和Plugin的区别
Nov 09 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
如何分别全角和半角以避免乱码
2006/10/09 PHP
PHP设计模式之解释器模式的深入解析
2013/06/13 PHP
PHP遍历某个目录下的所有文件和子文件夹的实现代码
2013/06/28 PHP
解析php中curl_multi的应用
2013/07/17 PHP
PHPThumb图片处理实例
2014/05/03 PHP
php获取发送给用户的header信息的方法
2015/03/16 PHP
使用PHP如何实现高效安全的ftp服务器(一)
2015/12/20 PHP
Javascript 更新 JavaScript 数组的 uniq 方法
2008/01/23 Javascript
通用JS事件写法实现代码
2009/01/07 Javascript
jquery 实现表单验证功能代码(简洁)
2012/07/03 Javascript
捕获和分析JavaScript Error的方法
2014/03/25 Javascript
js获取select默认选中的Option并不是当前选中值
2014/05/07 Javascript
两种方法基于jQuery实现IE浏览器兼容placeholder效果
2014/10/14 Javascript
javascript解三阶幻方(九宫格)
2015/04/22 Javascript
JS获取CSS样式(style/getComputedStyle/currentStyle)
2016/01/19 Javascript
模仿password输入框的实现代码
2016/06/07 Javascript
jquery实现瀑布流效果 jquery下拉加载新数据
2016/12/12 Javascript
Python格式化压缩后的JS文件的方法
2015/03/05 Python
python过滤字符串中不属于指定集合中字符的类实例
2015/06/30 Python
python编程线性回归代码示例
2017/12/07 Python
简单实现python进度条脚本
2017/12/18 Python
Python实现定时执行任务的三种方式简单示例
2019/03/30 Python
解决Tensorflow 使用时cpu编译不支持警告的问题
2020/02/03 Python
Python yield的用法实例分析
2020/03/06 Python
Python json读写方式和字典相互转化
2020/04/18 Python
利用pandas向一个csv文件追加写入数据的实现示例
2020/04/23 Python
python用700行代码实现http客户端
2021/01/14 Python
不同浏览器对CSS3和HTML5的支持状况
2009/10/31 HTML / CSS
html5新特性与用法大全
2018/09/13 HTML / CSS
HTML5 Canvas实现平移/放缩/旋转deom示例(附截图)
2013/07/04 HTML / CSS
HTML5 WebSocket实现点对点聊天的示例代码
2018/01/31 HTML / CSS
初中美术教学反思
2014/01/29 职场文书
2014收银员工作总结范文
2014/12/16 职场文书
五好家庭申报材料
2014/12/20 职场文书
运动会宣传语
2015/07/13 职场文书
日本十大血腥动漫,那些被禁播的动漫盘点
2022/03/21 日漫