行动计划

    

  • AppComponent变成应用程序的“壳”,它只'处理导航'

  • 把现在由AppComponent关注的英雄们移到一个独立的GeneralComponent

  • 添加路由

  • 创建一个新的DashboardComponent组件

  • 仪表盘加入导航结构中

路由是导航的另一个名字。路由器就是从一个视图导航到另一个视图的机制。

拆分Appcomponent.


    

现在的应用会加载AppComponent组件,并且立刻显示出英雄列表。

我们修改后的应用将提供一个壳,它会选择仪表盘英雄列表视图之一,然后默认显示它。

  AppComponent组件应该只处理导航。 我们来把英雄列表的显示职责,从AppComponent移到GeneralComponent组件中。

GeneralComponent组件

AppComponent的职责已经被移交给GeneralComponent了。 与其把AppComponent中所有的东西都搬过去,不如索性把它改名为GeneralComponent,然后单独创建一个新的AppComponent壳。

步骤:

1.把app.component.ts 和app.component.html 和app.component.scss移入到General文件夹下。

2.app改为generals

3.类名AppComponent改为GeneralsComponent

4.选择器名称app-root改为my-general

创建AppComponent

新的AppComponent将成为应用的“壳”。 它将在顶部放一些导航链接,并且把我们要导航到的页面放在下面的显示区中。

                     在./app下创建app.component.ts

  • 添加支持性的import语句。

  • 定义一个导出的 AppComponent类。

  • 在类的上方添加@Component元数据装饰器,装饰器带有app-root选择器。

  • 将下面的项目从HeroesComponent移到AppComponent

  • title类属性

  • @Component模板中的<h1>标签,它包含了对title属性的绑定。

  • 在模板的标题下面添加<my-heroes>标签,以便我们仍能看到英雄列表。

  • 添加GeneralComponent组件到根模块的declarations数组中,以便 Angular 能认识<my-generals>标签。

  • 添加GeneralServiceAppModuleproviders数组中,因为我们的每一个视图都需要它。

  • GeneralComponentproviders数组中移除GeneralService,因为它被提到模块了。

  • AppComponent添加一些import语句。

./app/app.component.ts

import { Component } from '@angular/core';

@Component({

selector: 'app-root',

template: `

<my-generals></my-generals>

`

})

export class AppComponent {

}

./app/app.module.ts

import { NgModule } from '@angular/core';

import { BrowserModule } from '@angular/platform-browser';

import { FormsModule }   from '@angular/forms';

import {GeneralService} from'./general.service';

//注册指令--->用法类似于组件

import {HighlightDirective} from '../directive/drag.directive';

//测试管道所用的组件

import {HeroBirthdayComponent} from "../Pipes/hero-birthday1.component";

import {ExponentialStrengthPipe} from "../Pipes/exponential-strength.pipe"

import {GeneralsComponent} from './general/generals.component';

import { AppComponent } from './app.component';

import {GeneralDetailComponent} from './general/general-detail.component';

@NgModule({

//列出程序中的组件

declarations: [

AppComponent,

GeneralDetailComponent,

GeneralsComponent,

// HighlightDirective,

// HeroBirthdayComponent,

// ExponentialStrengthPipe

],

//导入模块

imports: [

/*BrowserModule,每个运行在浏览器中的应用都必须导入它。

BrowserModule注册了一些关键的应用“服务”提供商。 它还包括了一些通用的指令,

例如NgIf和NgFor,所以这些指令在该模块的任何组件模板中都是可用的。

*/

BrowserModule,

//双向数据绑定依赖的模块

FormsModule

],

providers: [GeneralService],

/*@NgModule.bootstrap属性把这个AppComponent标记为引导 (bootstrap) 组件。

当 Angular 引导应用时,它会在 DOM 中渲染AppComponent,并把结果放进index.html的<app-root>元素标记内部。

*/

bootstrap: [AppComponent]

})

export class AppModule { }

./app/general/generals.component.ts

import { Component,OnInit} from '@angular/core';

import {General}  from "../../bean/General";

import {GeneralService} from'../general.service';

@Component({

selector: 'my-generals',

templateUrl: './generals.component.html',

styleUrls: ['./generals.component.scss']

})

export class GeneralsComponent implements OnInit {

title = 'MY General';

// generals:General[]=Generals;

color="pink";

constructor(private generalService:GeneralService ){

}

selectGeneral:General;

generals:General[];

getGenerals():void{

this.generalService.getGenerals()

.then(generals=>this.generals=generals);

}

ngOnInit(){

this.getGenerals();

}

oSelect(item:General):void{

this.selectGeneral=item;

}

}

添加路由

        

我们希望在用户点击按钮之后才显示英雄列表,而不是自动显示。 换句话说,我们希望用户能“导航”到英雄列表。

我们要使用 Angular 路由器进行导航。

Angular 路由器是一个可选的外部 Angular NgModule,名叫RouterModule。 路由器包含了多种服务(RouterModule)、多种指令(RouterOutlet、RouterLink、RouterLinkActive)、 和一套配置(Routes)。我们将先配置路由。

<base href> 组件

打开src/index.html

确保它的<head>区顶部有一个<base href="...">元素(或动态生成该元素的脚本)

配置路由 ./app/app.module.ts

a.导入路由所需要的模块

import { RouterModule }   from '@angular/router';

b.在imports下写入

RouterModule.forRoot([

{

path: 'generals',

component: GeneralsComponent

}

])

这个Routes是一个路由定义的数组。 此时,我们只有一个路由定义,但别急,后面还会添加更多。

路由定义包括以下部分:

  • Path: 路由器会用它来匹配浏览器地址栏中的地址,如generals

  • Component: 导航到此路由时,路由器需要创建的组件(GeneralsComponent)。

这里使用了forRoot()方法,因为我们是在应用根部提供配置好的路由器。 forRoot()方法提供了路由需要的“”路由服务提供商和指令”,并基于当前浏览器 URL 初始化导航。

路由出口(Outlet)

如果我们把路径/generals粘贴到浏览器的地址栏,路由器会匹配到'Generals'路由,并显示GeneralsComponent组件。 我们必须告诉路由器它位置,所以我们把<router-outlet>标签添加到模板的底部。 RouterOutlet是由RouterModule提供的指令之一。 当我们在应用中导航时,路由器就把激活的组件显示在<router-outlet>里面。

路由器链接

我们当然不会真让用户往地址栏中粘贴路由的 URL, 而应该在模板中的什么地方添加一个锚标签。点击时,就会导航到GeneralsComponent组件。

<a routerLink="/generals">Generals</a>

注意,锚标签中的[routerLink]绑定。 我们把RouterLink指令(ROUTER_DIRECTIVES中的另一个指令)绑定到一个字符串。 它将告诉路由器,当用户点击这个链接时,应该导航到哪里。

由于这个链接不是动态的,我们只要用一次性绑定的方式绑定到路由的路径 (path) 就行了。 回来看路由配置表,我们清楚的看到,这个路径 —— '/heroes'就是指向HeroesComponent的那个路由的路径。

现在./app/app.component.ts

import { Component } from '@angular/core';

@Component({

selector: 'app-root',

template: `

<a routerLink="/generals">Generals</a>

<router-outlet></router-outlet>

`

})

export class AppComponent {

}

AppComponent现在加上了路由器,并能显示路由到的视图了。 因此,为了把它从其它种类的组件中区分出来,我们称这类组件为路由器组件

添加一个仪表盘

当我们有多个视图的时候,路由才有意义。所以我们需要另一个视图。先创建一个DashboardComponent的占位符,让用户可以导航到它或从它导航出来。

在./src/app下创建dashboard文件夹

在这下面创建dashboard.component.ts

import { Component } from '@angular/core';

@Component({

selector: 'my-dashboard',

template: '<h3>My Dashboard</h3>'

})

export class DashboardComponent { }

我们先不实现他

配置仪表盘路由

要让app.module.ts能导航到仪表盘,就要先导入仪表盘组件,然后把下列路由定义添加到Routes数组中。

{

path: 'dashboard',

component: DashboardComponent

},

然后还得把DashboardComponent添加到AppModuledeclarations数组中。

DashboardComponent

添加重定向路由

浏览器启动时地址栏中的地址是/。 当应用启动时,它应该显示仪表盘,并且在浏览器的地址栏显示URL:/dashboard,把下列路由定义添加到Routes数组中。

{

path: '',

redirectTo: '/dashboard',

pathMatch: 'full'

},

添加导航到模版中

在模板上添加一个到仪表盘的导航链接,就放在Generals(英雄列表)链接的上方。

<a routerLink="/generals">Generals</a>

<a routerLink="/dashboard">Dashboard</a>

<router-outlet></router-outlet>

刷新浏览器。应用显示出了仪表盘,并可以在仪表盘和英雄列表之间导航了。

把英雄添加到仪表盘

让仪表盘变得有趣。

把元数据中的template属性替换为templateUrl属性,它将指向一个新的模板文件。

templateUrl: './dashboard.component.html'

增加styleUrls:['./dashboard.component.scss']

dashboard.component.htm

<h3>Top Generals</h3>

<div>

<div *ngFor="let general of generals" class="col-1-4">

<div>

<h4>`general`.`name`</h4>

</div>

</div>

</div>

我们再次使用*ngFor来在英雄列表上迭代,并显示它们的名字。 还添加了一个额外的<div>元素,来帮助稍后的美化工作。

dashboard.component.ts

import { Component,OnInit} from '@angular/core';

import {General}  from "../../bean/General";

import {GeneralService} from'../general.service';

@Component({

selector: 'my-dashboard',

templateUrl: './dashboard.component.html',

styleUrls:['./dashboard.component.scss']

})

export class DashboardComponent implements OnInit {

generals:General[];

constructor(private generalService:GeneralService){}

ngOnInit(){

this.generalService.getGenerals().then(generals=>this.generals=generals.slice(1,5));

}

}

我们在之前的GeneralsComponent中也看到过类似的逻辑:

  • 创建一个generals数组属性。

  • 在构造函数中注入GeneralService,并且把它保存在一个私有的generalService字段中。

  • 在 Angular 的ngOnInit生命周期钩子里面调用服务来获得英雄数据。

在仪表盘中我们用Array.slice方法提取了四个英雄(第2、3、4、5个)。

刷新浏览器,在这个新的仪表盘中就看到了四个英雄。

导航到英雄详情

虽然我们在HeroesComponent组件的底部显示了所选英雄的详情, 但用户还没法导航GeneralDetailComponent组件。我们可以用下列方式导航到GeneralDetailComponent

  • Dashboard(仪表盘)导航到一个选定的英雄。

  • Generals(英雄列表)导航到一个选定的英雄。

  • 把一个指向该英雄的“深链接” URL 粘贴到浏览器的地址栏。

    路由到一个英雄详情

我们将在app.module.ts中添加一个到GeneralDetailComponent的路由,也就是配置其它路由的地方。

这个新路由的不寻常之处在于,我们必须告诉GeneralDetailComponent该显示哪个英雄。 之前,我们不需要告诉GeneralsComponent组件和DashboardComponent组件任何东西

参数化路由

我们可以把英雄的id添加到 URL 中。当导航到一个id为 11 的英雄时,我们期望的 URL 是这样的:

/detail/11

URL中的/detail/部分是固定不变的,但结尾的数字id部分会随着英雄的不同而变化。 我们要把路由中可变的那部分表示成一个参数 (parameter) 令牌 (token) ,代表英雄的id

配置带参数的路由

{

path: 'detail/:id',

component: GeneralDetailComponent

},

路径中的冒号 (:) 表示:id是一个占位符,当导航到这个GeneralDetailComponent组件时,它将被填入一个特定英雄的id

修改GeneralDetailComponent

模板不用修改,我们会用原来的方式显示英雄。导致这次大修的原因是如何获得这个英雄的数据。

我们不会再从父组件的属性绑定中接收英雄数据。 新的GeneralDetailComponent 应该从ActivatedRoute服务的可观察对象params中取得id参数, 并通过GeneralService服务获取具有这个指定id的英雄数据。

先添加下列导入语句:

import { Component, Input, OnInit } from '@angular/core';

import { ActivatedRoute, ParamMap } from '@angular/router';

import { Location }                 from '@angular/common';

import 'rxjs/add/operator/switchMap';

import {GeneralService} from'../general.service';

然后注入ActivatedRouteHeroService服务到构造函数中,将它们的值保存到私有变量中:

constructor( private generalService: GeneralService,

private route: ActivatedRoute,

private location: Location){}

ngOnInit()生命周期钩子中,我们从ActivatedRoute服务的可观察对象params中提取id参数, 并且使用GeneralService来获取具有这个id的英雄数据。

ngOnInit(){

this.route.paramMap

.switchMap((params: ParamMap) => this.generalService.getGeneral(+params.get('id')))

.subscribe(general => this.general = general);

}

添加 GeneralService.getGeneral()

在前面的代码片段中GeneralService没有getGeneral()方法。要解决这个问题,请打开GeneralService并添加一个getGenera()方法,它会根据idgetGenerals()中过滤英雄列表。

etGeneral(id: number): Promise<General> {

return this.getGenerals()

.then(generals => generals.find(general => general.id === id));

}


回到原路

一个goBack()方法,它使用之前注入的Location服务, 利用浏览器的历史堆栈,导航到上一步。

goBack(): void {

this.location.back();

}

然后,我们通过一个事件绑定把此方法绑定到模板底部的 Back(后退)按钮上。

<button (click)="goBack()">Back</button>

选择一个仪表盘中的英雄

当用户从仪表盘中选择了一位英雄时,本应用要导航到GeneralDetailComponent以查看和编辑所选的英雄。

虽然仪表盘英雄被显示为像按钮一样的方块,但是它们的行为应该像锚标签一样。 当鼠标移动到一个英雄方块上时,目标 URL 应该显示在浏览器的状态条上,用户应该能拷贝链接或者在新的浏览器标签页中打开英雄详情视图。

要达到这个效果,再次打开dashboard.component.html,将用来迭代的<div *ngFor...>替换为<a>,就像这样:

刷新浏览器,并从仪表盘中选择一位英雄,应用就会直接导航到英雄的详情。

重构路由为一个模块

AppModule中有将近 20 行代码是用来配置四个路由的。 绝大多数应用有更多路由,并且它们还有守卫服务来保护不希望或未授权的导航。  路由的配置可能迅速占领这个模块,并掩盖其主要目的,即为 Angular 编译器设置整个应用的关键配置。

我们应该重构路由配置到它自己的类。 什么样的类呢? 当前的RouterModule.forRoot()产生一个Angular ModuleWithProviders,所以这个路由类应该是一种模块类。 它应该是一个路由模块

按约定,路由模块的名字应该包含 “Routing”,并与导航到的组件所在的模块的名称看齐。

app.module.ts所在目录创建app-routing.module.ts文件。将下面从AppModule类提取出来的代码拷贝进去:

import { NgModule }             from '@angular/core';

import { RouterModule, Routes } from '@angular/router';

import {GeneralsComponent} from './general/generals.component';

import {DashboardComponent} from './dashboard/dashboard.component';

import {GeneralDetailComponent} from './general/general-detail.component';

const routes: Routes = [

{ path: '', redirectTo: '/dashboard', pathMatch: 'full' },

{ path: 'dashboard',  component: DashboardComponent },

{ path: 'detail/:id', component: GeneralDetailComponent },

{ path: 'generals',     component: GeneralsComponent }

];

@NgModule({

imports: [ RouterModule.forRoot(routes) ],

exports: [ RouterModule ]

})

export class AppRoutingModule {}

  • 将路由抽出到一个变量中。如果你将来要导出这个模块,这种 "路由模块" 的模式也会更加明确。

  • 添加RouterModule.forRoot(routes)imports

  • RouterModule添加到路由模块的exports中,以便关联模块(比如AppModule)中的组件可以访问路由模块中的声明,比如RouterLink 和 RouterOutlet

  • declarations!声明是关联模块的任务。

  • 如果有守卫服务,把它们添加到本模块的providers中(本例子中没有守卫服务)。

修改 AppModule

删除AppModule中的路由配置,并导入AppRoutingModule (使用 ES import语句导入,并将它添加到NgModule.imports列表)。

import { NgModule } from '@angular/core';

import { BrowserModule } from '@angular/platform-browser';

import { FormsModule }   from '@angular/forms';

import {GeneralService} from'./general.service';

//路由所需要的核心模块

import { RouterModule }   from '@angular/router';

//路由模块

import {AppRoutingModule} from './app-routing.module'

//注册指令--->用法类似于组件

import {HighlightDirective} from '../directive/drag.directive';

//测试管道所用的组件

import {HeroBirthdayComponent} from "../Pipes/hero-birthday1.component";

import {ExponentialStrengthPipe} from "../Pipes/exponential-strength.pipe"

import {GeneralsComponent} from './general/generals.component';

import {DashboardComponent} from './dashboard/dashboard.component';

import { AppComponent } from './app.component';

import {GeneralDetailComponent} from './general/general-detail.component';

@NgModule({

//列出程序中的组件

declarations: [

AppComponent,

GeneralDetailComponent,

GeneralsComponent,

DashboardComponent

// HighlightDirective,

// HeroBirthdayComponent,

// ExponentialStrengthPipe

],

//导入模块

imports: [

/*BrowserModule,每个运行在浏览器中的应用都必须导入它。

BrowserModule注册了一些关键的应用“服务”提供商。 它还包括了一些通用的指令,

例如NgIf和NgFor,所以这些指令在该模块的任何组件模板中都是可用的。

*/

BrowserModule,

//双向数据绑定依赖的模块

FormsModule,

//路由模块

AppRoutingModule

],

providers: [GeneralService],

/*@NgModule.bootstrap属性把这个AppComponent标记为引导 (bootstrap) 组件。

当 Angular 引导应用时,它会在 DOM 中渲染AppComponent,并把结果放进index.html的<app-root>元素标记内部。

*/

bootstrap: [AppComponent]

})

export class AppModule { }

在 GeneralsComponent中选择一位英雄

添加 mini 版英雄详情

  在<div class="controller">  添加如下代码 

<div class="row">

<div *ngIf="selectGeneral">

<h2>

{{selectGeneral.name | uppercase}} is my hero

</h2>

<button (click)="gotoDetail()">View Details</button>

</div>

</div>

更新 GeneralsComponent类

点击按钮时,GeneralsComponent导航到GeneralDetailComponent。 该按钮的点击事件绑定到了gotoDetail()方法,它使用命令式的导航,告诉路由器去哪儿。

该方法需要对组件类做一些修改:

  1. 从 Angular 路由器库导入Router

  2. 在构造函数中注入Router(与HeroService一起)

  3. 实现gotoDetail(),调用路由器的navigate()方法

具体代码

import { Component,OnInit} from '@angular/core';

import { Router } from '@angular/router';

import {General}  from "../../bean/General";

import {GeneralService} from'../general.service';

@Component({

selector: 'my-generals',

templateUrl: './generals.component.html',

styleUrls: ['./generals.component.scss']

})

export class GeneralsComponent implements OnInit {

title = 'MY General';

// generals:General[]=Generals;

color="pink";

constructor(private generalService:GeneralService,private router: Router){

}

selectGeneral:General;

generals:General[];

getGenerals():void{

this.generalService.getGenerals()

.then(generals=>this.generals=generals);

}

ngOnInit(){

this.getGenerals();

}

oSelect(item:General):void{

this.selectGeneral=item;

}

gotoDetail(): void {

this.router.navigate(['/detail', this.selectGeneral.id]);

}

}

刷新浏览器,并开始点击。 我们能在应用中导航:从仪表盘到英雄详情再回来,从英雄列表到 mini 版英雄详情到英雄详情,再回到英雄列表。 我们可以在仪表盘和英雄列表之间跳来跳去。



本文转自 沉迷学习中 51CTO博客,原文链接:http://blog.51cto.com/12907581/1967223,如需转载请自行联系原作者

Angular2官网项目 (4)--路由相关推荐

  1. Django打造大型企业官网-项目实战(三)

    Django打造大型企业官网-项目实战(三) 一.CRM 后台管理系统 前面我们使用的是 xadmin 后台管理系统,在使用中发现,在权限限制中,我们能实现不同等级的用户/管理(超级管理员/管理员/用 ...

  2. Django打造大型企业官网-项目实战(四)

    Django打造大型企业官网-项目实战(四) 一.新闻相关功能 在项目实战三中,我们完成了新闻分类相关的一些功能,现在我们来完成新闻列表.发布新闻.编辑新闻.删除新闻的功能 1.发布新闻/编辑新闻 功 ...

  3. Django打造大型企业官网-项目部署

    Django打造大型企业官网-项目部署 一.准备工作 1.在开发机上的准备工作 1)确认项目没有bug. 2)打开终端,进入虚拟环境,再 cd 到项目根目录下,执行命令:pip freeze > ...

  4. 仿照小米官网项目具体操作与细节

    本项目已上传github 有需要的可以下载 点这里前往下载 小米官网项目具体操作 1.gulp的搭建 一 , 打开node控制台 命令行输入 cd 加文件夹路径 进入当前文件夹 命令行输入 cnpm ...

  5. 学院官网项目三级页面总结

    学院官网项目三级页面总结 (撰写时间:2019年7月6作者:李梦熙) 这个六月我来到了这个项目班,在这一个多月的时间里,虽然有时候还是不知道去做些什么,但是我在这里也学习到了很多项目管理和分配工作之类 ...

  6. 如何用Nuxt.js构建项目,SSR官网项目搭建流程

    SSR渲染 现在Vue,React,angular等三大框架引领的单页面应用大行其道,使用这单页面技术构建的项目比比皆是.这些流行的框架给我们带来的好处显而易见,不仅是开发,维护成本都大大地获得了优化 ...

  7. 小米官网项目制作——javascript知识分享上

    目录 前言 一.整体架构 二.弹出的盒子 1.定位盒子 2.弹出效果 3.其他细节 三.下拉,展开的切换菜单 1.放置盒子 2.切换盒子 3.添加索引 4.侧边展开的盒子 四.轮播图 1.本体的部件 ...

  8. 小米官网项目制作——javascript知识分享下

    目录 前言 一.观察页面内容 二.切换界面 三.登录表单界面 1.选中的效果 2.错误提示 3.不选中的效果 4.密码框 四.注册界面 五.链接跳转 总结 前言 之前我分享了关于小米官网主页的java ...

  9. HTML5期末大作业:基于html企业官网项目的设计与实现【艺术官网】

最新文章

  1. 实战课【1】jQuery实现表单校验及布局
  2. Linux基础命令---ipcs显示进程tong
  3. 打桥位lisp_lisp函数
  4. mysql数据库简单介绍_数据库的简单介绍
  5. Eclipse中clean项目的作用
  6. 理论 | 当 Spring Boot 遇上了消息队列......
  7. C++新特性探究(十三):右值引用(r-value ref)探究
  8. Altium Designer
  9. android中表情功能实现,android sina 微博表情功能的实现
  10. c语言版本双人贪吃蛇
  11. 3Ds Max动画课程设计
  12. 一个div实现太极图案+动画(简单易懂)
  13. 华硕FX63VM笔记本bios如何设置U盘启动
  14. upupoo视频使用Java代码下载
  15. ig信息增益 java_【Python 编程】实现文本分类中的信息增益算法
  16. Sigar获取系统信息
  17. 笔记 | spark安装及入门会遇到哪些坑
  18. 参考一:双缝干涉与波长测量
  19. 禁止灵格斯2.7弹出“新奇英语 互动锐词”广告窗口的解决方法
  20. Python 3.6实现单博主微博文本、图片及热评爬取

热门文章

  1. JAVA语法——经典题目01
  2. 51nod 1623 完美消除(数位DP)
  3. 朴素贝叶斯和贝叶斯估计
  4. 【Step1】【floyd】poj1125-Stockbroker Grapevine
  5. WPF中StringToImage和BoolToImage简单用法
  6. 微信支付现金红包接口(转)
  7. IOS-C语言第12天,(函数指针)Point and macro(宏)
  8. windows下的diskpart指令彻底格式化清除U盘
  9. java list 自定义类型转换_使用Java Stream API将List按自定义分组规则转换成Map的一个例子...
  10. idea创建Package时出现包名累加,而不是树形结构解决方法