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

这里是主页组件

product.component.html

这里是商品信息组件

添加路由配置

修改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页面模版。


主页
商品详情


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

运行项目

ng serve --open运行项目。

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


主页
商品详情



其中在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页面模版内容。

404 Not Found!

路由配置,修改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页面模版。


主页
商品详情



点击页面商品详情链接,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值。

这里是商品信息组件

商品ID是: {{productId}}

修改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路由链接的参数来传递数据。


主页
商品详情



点击页面商品详情链接,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。

什么是参数快照?什么是参数订阅?

参数快照就是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模版页面内容。

这是一个商品描述页面

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

销售员ID是:{{sellerId}}

修改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模版页面,添加路由选项。

这里是商品信息组件

商品ID是: {{productId}}

商品描述 销售员信息

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

辅助路由




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

Xxx
Yyy

新建聊天组件

ng g component chat

修改模版页面内容


修改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路由链接的参数来传递数据。


主页
商品详情

开始聊天
结束聊天


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

开始聊天

路由守卫

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

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

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

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 {

  constructor(private router: Router) {

  }

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable | Promise | 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

这里是商品信息组件

商品ID是: {{productId}}

商品名称是: {{productName}}

商品描述 销售员信息

你可能感兴趣的:(Angular Route导航)