Angular Route导航

Angular Route导航

路由基础知识

路由相关对象介绍

名称 简介
Routes 路由配置,保存着哪个URL对应展示哪个组件,以及在哪个RouterOutlet中展示组件。
RouterOutlet 在Html中标记路由内容呈现位置的占位符指令。
Router 负责在运行时执行路由的对象,可以通过调用其navigate()和navigateByUrl()方法来导航到一个指定的路由。
RouterLink 在Html中声明路由导航用的指令。
ActivatedRoute 当前激活的路由对象,保存着当前路由的信息,如路由地址,路由参数等。

新建路由项目

使用angular-cli新建项目。

ng new router --routing

新生成一个带有app-routing.module.ts路由模块的项目。

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

const routes: Routes = [];

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

app.module.ts模块中会导入AppRoutingModule模块。

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

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

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule   <<=== add here
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

再生成homeproduct组件。

ng g component home
ng g component product

修改新建组件内容

home.component.html

<p>
  这里是主页组件
</p>

product.component.html

<p>
  这里是商品信息组件
</p>

添加路由配置

修改app-routin.module.ts路由配置文件。

import {NgModule} from '@angular/core';
import {Routes, RouterModule} from '@angular/router';
import {HomeComponent} from './home/home.component';
import {ProductComponent} from './product/product.component';

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

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

修改app.component.html页面模版。

<!--The content below is only a placeholder and can be replaced.-->
<a [routerLink]="['/']">主页</a>
<a [routerLink]="['/product']">商品详情</a>

<router-outlet></router-outlet>

routerLink参数是数组类型,以便传递参数。

运行项目

ng serve --open运行项目。

修改app.component.html给页面模版添加一个商品详情按钮。

<!--The content below is only a placeholder and can be replaced.-->
<a [routerLink]="['/']">主页</a>
<a [routerLink]="['/product']">商品详情</a>
<input type="button" value="商品详情" (click)="toProductDetails()">

<router-outlet></router-outlet>

其中在app.component.ts实现toproductDetails()方法

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 = 'router';

  constructor(private router: Router) {

  }

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

这里方法中使用Routernavigate方法实现路由跳转。

这里routeLink是通过前端页面实现跳转,而navigate是通过后台组件实现跳转。

实现访问不存在页面跳转

创建code404组件,实现默认跳转页面。

ng g component code404

code404.component.html页面模版内容。

<p>
  404 Not Found!
</p>

路由配置,修改app-routing.module.ts,添加页面不存时显示页面。

import {NgModule} from '@angular/core';
import {Routes, RouterModule} from '@angular/router';
import {HomeComponent} from './home/home.component';
import {ProductComponent} from './product/product.component';
import {Code404Component} from './code404/code404.component';

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

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

路由器使用先匹配者优先选择原则,所以通配符路由要放在路由配置的最后面。

路由时传递数据

第一种方式

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

第二种方式

{path: /product/:id}  =>  /product/1  =>  ActivateRoute.params[id]

第三种方式

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

修改app.component.html页面模版。

<!--The content below is only a placeholder and can be replaced.-->
<a [routerLink]="['/']">主页</a>
<a [routerLink]="['/product']" [queryParams]="{id: 1}">商品详情</a>
<input type="button" value="商品详情" (click)="toProductDetails()">

<router-outlet></router-outlet>

点击页面商品详情链接,URL跳转变为http://localhost:4200/product?id=1

下面来看看怎么在商品详情组件中接受这个传递参数。

首先在商品详情组件product.component.ts中注入ActivatedRoute组件,然后在其中声明一个productId来接收传进来的id,如第一种方式所示,使用queryParams获取传递值。

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'];
  }

}

页面上展示ID值。

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

修改app-routing.module.ts路由配置中的path属性使其可以携带参数。

import {NgModule} from '@angular/core';
import {Routes, RouterModule} from '@angular/router';
import {HomeComponent} from './home/home.component';
import {ProductComponent} from './product/product.component';
import {Code404Component} from './code404/code404.component';

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

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

然后修改app.component.html路由链接的参数来传递数据。

<!--The content below is only a placeholder and can be replaced.-->
<a [routerLink]="['/']">主页</a>
<a [routerLink]="['/product', 1]">商品详情</a>
<input type="button" value="商品详情" (click)="toProductDetails()">

<router-outlet></router-outlet>

点击页面商品详情链接,URL跳转变为http://localhost:4200/product/1

如第二种方式,修改商品详情组件product.component.ts,将queryParams改为params即可。

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.params['id'];
  }

}

点击商品详情链接页面上展示ID值为1。

<u>什么是参数快照?什么是参数订阅?</u>

参数快照就是snapshot,这里如果切换商品详情页面,虽然URL会来回切换,但是ID的显示值并不会改变。所以采用参数订阅方式。

参数订阅,subscribe

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;

  constructor(private routeInfo: ActivatedRoute) {
  }

  ngOnInit() {
    // this.productId = this.routeInfo.snapshot.params['id'];
    this.routeInfo.params.subscribe((params: Params) => this.productId = params['id']);
  }

}

重定向路由

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

www.aaa.com  =>  www.aaa.com/products

www.aaa.com/x  =>  www.aaa.com/y

修改app-routing.module.ts,添加重定向路由。

import {NgModule} from '@angular/core';
import {Routes, RouterModule} from '@angular/router';
import {HomeComponent} from './home/home.component';
import {ProductComponent} from './product/product.component';
import {Code404Component} from './code404/code404.component';

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

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

子路由

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

新建商品描述组件和商品销售员组件。

ng g component product-descng g component seller-info

修改product-desc.component.html模版页面内容。

<p>
  这是一个商品描述页面
</p>

修改seller-info.component.html模版页面内容,并传递sellerId

<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,添加商品子路由配置。

import {NgModule} from '@angular/core';
import {Routes, RouterModule} from '@angular/router';
import {HomeComponent} from './home/home.component';
import {ProductComponent} from './product/product.component';
import {Code404Component} from './code404/code404.component';
import {ProductDescComponent} from './product-desc/product-desc.component';
import {SellerInfoComponent} from './seller-info/seller-info.component';

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

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

然后修改product.component.html模版页面,添加路由选项。

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

这里./表示当前页面下面的路由选项这里就是http://localhost:4200/product/1/seller/99

辅助路由

<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>

新建聊天组件

ng g component chat

修改模版页面内容

<textarea placeholder="content" class="chat"></textarea>

修改app-routing.module.ts,添加辅助路由配置。

import {NgModule} from '@angular/core';
import {Routes, RouterModule} from '@angular/router';
import {HomeComponent} from './home/home.component';
import {ProductComponent} from './product/product.component';
import {Code404Component} from './code404/code404.component';
import {ProductDescComponent} from './product-desc/product-desc.component';
import {SellerInfoComponent} from './seller-info/seller-info.component';
import {ChatComponent} from './chat/chat.component';

const routes: Routes = [
  {path: '', redirectTo: '/home', pathMatch: 'full'},
  {path: 'chat', component: ChatComponent, outlet: 'aux'},
  {path: 'home', component: HomeComponent},
  {
    path: 'product/:id', component: ProductComponent,
    children: [
      {path: '', component: ProductDescComponent},
      {path: 'seller/:id', component: SellerInfoComponent}
    ]
  },
  {path: '**', component: Code404Component}
];

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

然后修改app.component.html路由链接的参数来传递数据。

<!--The content below is only a placeholder and can be replaced.-->
<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>

如果想同时指定这时主路由的跳转,还请修改为

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

路由守卫

只有当用户已经登录并拥有某些权限时才能进入某些路由。

一个由多个表单组件组成的向导,例如注册流程,用户只有在当前路由的组件中填写了满足要求的信息才可以导航到下一个路由。

当用户未执行保存操作而试图离开当前导航时提醒用户。

CanActivate:处理导航到某路由的情况。

CanDeactivate:处理从当前路由离开的情况。

Resolve:在路由激活之前获取路由数据。

添加自定义路由守卫login.guard.ts

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

export class LoginGuard implements CanActivate {
  canActivate() {
    let loginIn: boolean = Math.random() < 0.5;
    if (!loginIn) {
      console.log('用户未登录');
    }
    return loginIn;
  }
}

修改app-routing.module.ts,添加路由守卫配置。

import {NgModule} from '@angular/core';
import {Routes, RouterModule} from '@angular/router';
import {HomeComponent} from './home/home.component';
import {ProductComponent} from './product/product.component';
import {Code404Component} from './code404/code404.component';
import {ProductDescComponent} from './product-desc/product-desc.component';
import {SellerInfoComponent} from './seller-info/seller-info.component';
import {ChatComponent} from './chat/chat.component';
import {LoginGuard} from './guard/login.guard';

const routes: Routes = [
  {path: '', redirectTo: '/home', pathMatch: 'full'},
  {path: 'chat', component: ChatComponent, outlet: 'aux'},
  {path: 'home', component: HomeComponent},
  {
    path: 'product/:id', component: ProductComponent,
    children: [
      {path: '', component: ProductDescComponent},
      {path: 'seller/:id', component: SellerInfoComponent}
    ], canActivate: [LoginGuard]
  },
  {path: '**', component: Code404Component}
];

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

并且通过在providers添加LoginGuard来实现依赖注入。LoginGuard实现CanActivate方法。

CanDeactivate同理。

添加product.resolve.ts,如果productId值为1则创建新对象传递进商品详情页面,否则跳转到主页。

import {ActivatedRouteSnapshot, Resolve, Router, RouterStateSnapshot} from '@angular/router';
import {Observable} from 'rxjs';
import {Product} from '../product/product.component';
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']);
    }
  }
}

修改app-routing.module.ts,添加reslove路由守卫配置。

import {NgModule} from '@angular/core';
import {Routes, RouterModule} from '@angular/router';
import {HomeComponent} from './home/home.component';
import {ProductComponent} from './product/product.component';
import {Code404Component} from './code404/code404.component';
import {ProductDescComponent} from './product-desc/product-desc.component';
import {SellerInfoComponent} from './seller-info/seller-info.component';
import {ChatComponent} from './chat/chat.component';
import {LoginGuard} from './guard/login.guard';
import {ProductResolve} from './guard/product.resolve';

const routes: Routes = [
  {path: '', redirectTo: '/home', pathMatch: 'full'},
  {path: 'chat', component: ChatComponent, outlet: 'aux'},
  {path: 'home', component: HomeComponent},
  {
    path: 'product/:id', component: ProductComponent,
    children: [
      {path: '', component: ProductDescComponent},
      {path: 'seller/:id', component: SellerInfoComponent}
    ], resolve: {
      product: ProductResolve
    }
  },
  {path: '**', component: Code404Component}
];

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

resolve中参数是一个对象,product是想传递进去参数的名字,然后用ProductResolve来生成。

在商品信息组件中在声明productName

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.productId = this.routeInfo.snapshot.params['id'];
    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对象的idname赋予我本地的productIdproductName属性。

修改模版页面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>
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 一、SPA的概念 首先明确一个概念,SPA,全称为Single Page Application单页应用,一个单页...
    耦耦阅读 11,203评论 0 3
  • 路由是导航的另一个名字。路由器就是从一个视图导航到另一个视图的机制。 1.导航,那么我们专门做一个导航组件。这个组...
    价值投机168阅读 6,303评论 0 2
  • <1>输入属性 定义:组件的输入属性,是指被@input装饰器注解的属性,用来从父组件接收数据 实例1.新建ord...
    mumumuu阅读 3,641评论 0 1
  • 时间就这样,匆匆过去,转眼来这座城市13年,有收获,有遗憾,从什么都不懂的,像个傻子一样跌跌撞撞中成长,最大的幸福...
    wy你会好的阅读 1,346评论 0 0
  • 首先,50亿对我来说太多了,就我目前的水平根本没能力驾驭50亿,所以我压根就想不出50亿能干啥,以下所写的估计有2...
    田妞1999阅读 2,415评论 0 0

友情链接更多精彩内容