Angular4-在线竞拍应用-路由

angular是单页应用需要配置路由来实现页面跳转。
这里写图片描述

这里写图片描述

路由的例子

通过超链接导航

新建一个项目,ng new router --routing

然后用webstorm打开项目

生成项目时添加了–routing参数后,

会多生成一个app-routing.module.ts文件

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

const routes: Routes = [
  {
    path:'',
    children:  []
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
  providers:[]
})
export class AppRoutingModule { }

在app.module.ts中也会多引入AppRoutingModule

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import {FormsModule} from '@angular/forms';
import {HttpModule} from '@angular/http';

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

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

在app.component.html中会加入router-outlet

<h1>
  {{title}}
</h1>
<router-outlet></router-outlet>

新生成两个组件ng g component home,ng g component product

然后修改app-routing.modules.ts,为了保证通用性,这里写地址的时候不要在前面加上/

const routes: Routes = [
  {path:'',component:HomeComponent},
  {path:'product',component:ProductComponent}
];

修改app.component.html

<a [routerLink]="['/']">主页</a>
<a [routerLink]="['/product']">商品详情</a>

<router-outlet></router-outlet>

这里写图片描述

当我访问localhost:4200的时候显示的是home works!,当我点击商品详情,会显示product works!并且地址变成了localhost:4200/product

通过触发事件导航

修改app.component.html

<a [routerLink]="['/']">主页</a>
<a [routerLink]="['/product']">商品详情</a>
<input type="button" value="商品详情" (click)="toProductDetails()">
<router-outlet></router-outlet>
import { Component } from '@angular/core';
import {Router} from "@angular/router";
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';

  constructor(private router: Router){}

  toProductDetails(){
    this.router.navigate(['/product']);
  }
}

运行程序,点击按钮,下边就会显示product works!

配置404页面路由

新生成一个组件ng g component code404

修改app-routing.module.ts

const routes: Routes = [
  {path:'',component:HomeComponent},
  {path:'product',component:ProductComponent},
  {path:'**',component:Code404Component}
];

当访问一个不存在的路径时会显示code404 works!

显示路由是从上往下匹配地址,如果把{path:’**’,component:Code404Component}放到前面不管访问那个页面都会显示code404了。所以具有通用性的路由要放到最后边。

在路由中传递数据

在查询参数中传递数据

/product?id=1&name=2     =>   ActivatedRoute.queryParams[id]

在路由路径中传递数据

{path:/product/:id} =>/product/1  => ActivatedRoute.queryParams[id]

在路由配置中传递数据

{path:/product,component:ProductComponent,date[{isProd:true}]}
=> ActivatedRoute.data[0][isProd]

在查询参数中传递数据

修改app.component.html

<a [routerLink]="['/product']" [queryParams]="{id:1}">商品详情</a>

这样点击这个连接的时候地址就会为http://localhost:4200/product?id=1

修改product.component.ts

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

@Component({
  selector: 'app-product',
  templateUrl: './product.component.html',
  styleUrls: ['./product.component.css']
})
export class ProductComponent implements OnInit {
  private productId: number;

  constructor(private routeInfo: ActivatedRoute) {
  }

  ngOnInit() {
    this.productId = this.routeInfo.snapshot.queryParams["id"];
  }

}

修改product.component.html

<p>
  这里是商品信息组件
</p>
<p>
  商品ID是:{{productId}}
</p>

在路由路径中传递数据

修改app-routing.module.ts

 {path:'product/:id',component:ProductComponent},

修改app.component.html

<a [routerLink]="['/product',1]">商品详情</a>

修改product.component.ts

this.productId = this.routeInfo.snapshot.params["id"];

参数快照和参数订阅

修改app.component.ts,加了一个参数2

this.router.navigate(['/product',2]);

启动程序。我点击了主页链接后再点商品详情链接。我点击主页链接,然后点击商品详情按钮。都很正常,链接和下面显示的商品id都对应的上。

但是,当我点击商品详情链接之后,再点击商品详情按钮。地址栏由1变成了2,但下边显示的商品id却还是1。

从home组件到product组件会重新创建product组件重新调用ngOnInit方法。

从product组件到product组件,不会重新创建product组件,所以不会重新调用ngOnInt方法。

之前我们使用的都是snapshot,参数快照。

现在我们用参数订阅,subscribe,来解决这个问题

修改product.component.ts

    this.routeInfo.params.subscribe((params: Params)=>this.productId=params["id"]);

弄了一个匿名函数把传进来的params参数赋值给productId

这样做了之后就没有之前的问题了。

虽然商品详情组件没有被创建,但是参数变了,而我订阅了那个参数,每次我都能接受到改变了的那个值,然后把这个值赋值为productId。

在以后写代码中如果确定不会从自身路由到自身就可以用参数快照的方式。

如果不确定就要用参数订阅的方式来获取参数。

重定向路由

在用户访问一个特定的地址时,将其重定向到另一个指定的地址。

修改app-routing.module.ts

const routes: Routes = [
  {path:'',redirectTo:'/home',pathMatch:'full'},
  {path:'home',component:HomeComponent},
  {path:'product/:id',component:ProductComponent},
  {path:'**',component:Code404Component}
];

当我访问localhost:4200的时候会重定向到home

修改app.component.html

<a [routerLink]="['/home']">主页</a>

子路由

{path:'home',component:HomeComponent,
  children:[
  {
    path:'',component:XxxComponent
  },
  {
    path:'/yyy',component:YyyComponent
  }

  ]}

创建商品描述组件ng g component productDesc

创建销售员信息组件ng g component sellerInfo

修改product-desc.component.html

<p>
  这是一个牛X的商品!
</p>

修改seller-info.component.html

<p>
  销售员ID是:{{sellerId}}
</p>

修改seller-info.component.ts

import { Component, OnInit } from '@angular/core';
import {ActivatedRoute} from '@angular/router';
@Component({
  selector: 'app-seller-info',
  templateUrl: './seller-info.component.html',
  styleUrls: ['./seller-info.component.css']
})
export class SellerInfoComponent implements OnInit {
  private sellerId:number;
  constructor(private routeInfo:ActivatedRoute) { }

  ngOnInit() {
    this.sellerId=this.routeInfo.snapshot.params["id"];
  }

}

修改app-routing.module.ts

{path:'product/:id',component:ProductComponent,
    children:[
    {path:'',component:ProductDescComponent},
    {path:'seller/:id',component:SellerInfoComponent}
  ]},

修改product.component.html

<p>
  这里是商品信息组件
</p>
<p>
  商品ID是:{{productId}}
</p>
<a [routerLink]="['./']">商品描述</a>
<a [routerLink]="['./seller',99]">销售员信息</a>
<router-outlet></router-outlet>

/是从跟路由开始找,./是从当前路由开始找。

路由信息都是在模块层的,组件本身不知道关于路由的信息。

辅助路由

<router-outlet></router-outlet>
<router-outlet name="aux"></router-outlet>

{path:'xxx',component:XxxComponent,outlet:"aux"}
{path:'yyy',component:YyyComponent,outlet:"aux"}

<a [routerLink]="['/home',{outlets:{aux:'xxx'}}]">Xxx</a>
<a [routerLink]="['/product',{outlets:{aux:'yyy'}}]">Yyy</a>

以前一个组件中只可以定义一个插座,而现在可以定义多个插座。

辅助路由案例整体思路

  • 在app组件的目标上再定义一个插座来显示聊天面板
  • 单独开发一个聊天室组件,只显示在新定义的插座上
  • 通过路由参数控制新插座是否显示聊天面板

修改app.component.html,添加辅助路由

<router-outlet name="aux"></router-outlet>

新创建一个组件ng g component chat

修改chat.component.html

<textarea placeholder="请输入聊天内容" class="chat"></textarea>

修改chat.component.css

.chat{
  background:green;
  height:100px;
  width:30%;
  float: left;
  box-sizing:border-box;
}

修改product.component.html

<div class="product">
  <p>
    这里是商品信息组件
  </p>
  <p>
    商品ID是:{{productId}}
  </p>
  <a [routerLink]="['./']">商品描述</a>
  <a [routerLink]="['./seller',99]">销售员信息</a>
  <router-outlet></router-outlet>
</div>

修改product.component.css

.product{
  background:yellow;
  height:100px;
  width:70%;
  float: left;
  box-sizing:border-box;
}

修改home.component.html

<div class="home">
  <p>
    这里是主页组件
  </p>
</div>

修改home.component.css

.home{
  background:red;
  height:100px;
  width:70%;
  float: left;
  box-sizing:border-box;
}

修改app-routing.module.ts

 {path:'',redirectTo:'/home',pathMatch:'full'},
  {path:'chat',component:ChatComponent,outlet:'aux'},

修改app.component.html

<a [routerLink]="['/home']">主页</a>
<a [routerLink]="['/product',1]">商品详情</a>
<input type="button" value="商品详情" (click)="toProductDetails()">
<a [routerLink]="[{outlets:{aux:'chat'}}]">开始聊天</a>
<a [routerLink]="[{outlets:{aux:null}}]">结束聊天</a>
<router-outlet></router-outlet>
<router-outlet name="aux"></router-outlet>

修改app.component.html

<a [routerLink]="[{outlets:{primary:'home',aux:'chat'}}]">开始聊天</a>

当我点击开始聊天时,主路由会显示为home。

路由守卫

应用场景:

  • 只有当用户已经登录并拥有某些权限时才能进入某些路由。
  • 一个由多个表单组件组成的向导,例如注册流程,用户只有在当前路由的组件中填写了满足要求的信息才可以导航到下一个路由
  • 当用户未执行保存操作而试图离开当前导航时提醒用户

三种路由守卫

  • CanActivate:处理导航到某路由的情况
  • CanDeactivate:处理从当前路由离开的情况
  • Resolve:在路由激活之前获取路由数据

CanActivate守卫

app,右键,新建一个目录,名字为guard,右键guard,新建一个TypeScript文件,名字为login.guard.ts,填写代码

import {CanActivate} from "@angular/router";

export class LoginGuard implements CanActivate {

  canActivate() {
    let loggedIn: boolean = Math.random() < 0.5;
    if (!loggedIn) {
      console.log("用户未登陆");
    }
    return loggedIn;
  }

}

修改app-routing.module.ts

 {path:'product/:id',component:ProductComponent,children:[
    {path:'',component:ProductDescComponent},
    {path:'seller/:id',component:SellerInfoComponent}
  ],canActivate:[LoginGuard]},


  @NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
  providers:[LoginGuard]
})

CanDeactivate守卫

右键guard,新建一个TypeScript文件,名字为unsave.guard.ts

填写代码

import {ProductComponent} from "../product/product.component";
import {CanDeactivate} from "@angular/router";

export class UnsavedGuard implements CanDeactivate<ProductComponent>{

  canDeactivate(component: ProductComponent){
    return window.confirm("你还没有保存,确定要离开么?");
  }

}

修改app-routing.module.ts

{path:'product/:id',component:ProductComponent,children:[
  {path:'',component:ProductDescComponent},
  {path:'seller/:id',component:SellerInfoComponent}
],canActivate:[LoginGuard]
,canDeactivate:[UnsavedGuard]},

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
  providers:[LoginGuard,UnsavedGuard]
})

resolve守卫

解决的问题,在显示页面之前,页面中的数据显示的时候可能有延迟,这样显示数据的地方会都显示空。

这个守卫的作用就是,在显示页面之前预先到服务器去读数据

右键guard,新建一个TypeScript文件,名字为product.resolve.ts

import {Resolve,ActivatedRouteSnapshot,RouterStateSnapshot,Router} from "@angular/router";
import {Product} from "../product/product.component";
import {Observable} from "rxjs";
import {Injectable} from "@angular/core";

@Injectable()
export class ProductResolve implements Resolve<Product>{

  constructor(private router:Router){}

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Product> | Promise<Product> | Product {
    let productId:number=route.params["id"];
    if(productId==1){
      return new Product(1,"iPhone7")
    }else{
      this.router.navigate(['/home']);
      return undefined;
    }

  }
}

修改product.component.ts

import {Component, OnInit} from '@angular/core';
import {ActivatedRoute,Params} from "@angular/router";

@Component({
  selector: 'app-product',
  templateUrl: './product.component.html',
  styleUrls: ['./product.component.css']
})
export class ProductComponent implements OnInit {
  private productId: number;

  private productName:string;

  constructor(private routeInfo: ActivatedRoute) {
  }

  ngOnInit() {
    this.routeInfo.params.subscribe((params: Params)=>this.productId=params["id"]);

    this.routeInfo.data.subscribe((data:{product:Product})=>{
      this.productId=data.product.id;
      this.productName=data.product.name
    });
  }

}

export class Product{
  constructor(public id:number,public name:string){}
}

修改product.component.html

<div class="product">
  <p>
    这里是商品信息组件
  </p>
  <p>
    商品ID是:{{productId}}
  </p>
  <p>
    商品名称是:{{productName}}
  </p>
  <a [routerLink]="['./']">商品描述</a>
  <a [routerLink]="['./seller',99]">销售员信息</a>
  <router-outlet></router-outlet>
</div>

改造在线竞拍应用

步骤:

  • 创建商品详情组件,显示商品的图片和标题
  • 重构代码,把轮播图组件和商品列表组件封装到新的Home组件
  • 配置路由,在导航到商品详情组件时传递商品的标题参数
  • 修改App组件,根据路由显示Home组件或商品详情组件
  • 修改商品列表组件,给商品标题添加带routLink指令的链接,导航到商品详情路由

新建组件ng g component productDetail

修改product-detail.component.ts

import { Component, OnInit } from '@angular/core';
import{ActivatedRoute} from '@angular/router';
@Component({
  selector: 'app-product-detail',
  templateUrl: './product-detail.component.html',
  styleUrls: ['./product-detail.component.css']
})
export class ProductDetailComponent implements OnInit {

  productTitle:string;
  constructor(private routeInfo:ActivatedRoute) { }

  ngOnInit() {
    this.productTitle=this.routeInfo.snapshot.params["prodTitle"];
  }

}

修改product-detail.component.html

<div>
  <img src="http://placehold.it/820x230">
  <h4>{{productTitle}}</h4>
</div>

创建home组件,ng g component home

把app.component.css的内容剪切到home.component.css

把app.component.html中的以下内容复制到home.component.html

<div class="row carousel-container">
  <app-carousel></app-carousel>
</div>
<div class="row">
  <app-product></app-product>
</div>

并添加

<router-outlet></router-outlet>

到原来的位置

修改app.module.ts

const routeConfig:Routes=[
  {path:'',component:HomeComponent},
  {path:'product/:prodTitle',component:ProductDetailComponent}
]

 imports: [
    BrowserModule,
    RouterModule.forRoot(routeConfig)
  ],

修改product.component.html,增加routerLink

<h4><a [routerLink]="['/product'],product.title">{{product.title}}</a></h4>
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值