【6】 angular 路由基础知识_在路由时传递数据_重定向路由_子路由_辅助路由_路由守卫
发布日期:2021-05-07 19:12:51 浏览次数:13 分类:技术文章

本文共 15771 字,大约阅读时间需要 52 分钟。

 

路由基础知识

  路由相关对象介绍

 

 

新建一个项目

ng new router --routing

并使用webstrom 打开 

发现--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 也会导入这个模块

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  ],  providers: [],  bootstrap: [AppComponent]})export class AppModule { }

app.component.html 下面也会多一个插座

 

为了展示功能 先创建两个组件

ng g component home

ng g component product

修改 home.component.html

这里是主页组件

product.component.html

这是是商品信息组件

修改 app.component.html

主页商品详情

运行查看效果

选择商品的时候上面地址会自动变成

加个按钮  使用控制器跳转

主页商品详情

修改 app.component.ts

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

效果同routerLink

当用户使用不存在的路径

创建一个404组件

ng g component code404

修改 code404.component.html

页面不存在

修改 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   >>  ActivatedRoute.queryParams[id]

在路由的路径中传递数据

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

在路由配置中传递数据

{path:/product,comonent:ProductCompomemt,data[{isProd:true}]} >> ActivatedRoute.data[0][isProd]

下面我们继续修改demo 查看效果

 app.component.html

主页商品详情

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 {  public productId: number;  constructor(private routeInfo: ActivatedRoute) {  }  ngOnInit() {    this.productId = this.routeInfo.snapshot.queryParams['id'];  }}

这是是商品信息组件

商品Id是{ {productId}}

下面第二种方式

app.component.html

主页商品详情

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/:id', component: ProductComponent},  {path: '**', component: Code404Component},];@NgModule({  imports: [RouterModule.forRoot(routes)],  exports: [RouterModule]})export class AppRoutingModule {}

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 {  public productId: number;  constructor(private routeInfo: ActivatedRoute) {  }  ngOnInit() {    this.productId = this.routeInfo.snapshot.params['id'];  }}

在写第三种方式的时候  我们要明确两个概念  参数快照 和参数订阅

修改 app.component.ts

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

然后操作 网页

上面 主页  商品详情(p)  商品详情(button)  我们 称为1 2 3

点击 1  点击 3  效果正常 

点击 1 点击2  效果正常

点击 1 点击2 点击3 效果如上图所示

这是因为product.component.ts中的

ngOnInit() {    this.productId = this.routeInfo.snapshot.params['id'];  }

使用了参数快照  

我们改成参数订阅试一下

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 {  public productId: number;  constructor(private routeInfo: ActivatedRoute) {  }  ngOnInit() {    this.routeInfo.params.subscribe((params: Params) => this.productId = params['id']);  }}

 我们会发现 即使 点击 1 点击2 点击3 就可以了 效果就没问题了

重定向路由

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

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

修改路由配置

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' compenent:YyyComponent}]}

 当访问home 路径的时候 还是会展现Home组件的模版 但是 

router-outlet会显示Xxx组价模版

同理 访问home/yyy的时候 还是会展现Home组件的模版 但是 

router-outlet会显示Yyy组价模版

现在我们来一步一步来实现子路由

新建两个组件

ng g component productDescng g component sellerInfo

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

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 {  public sellerId: number;  constructor(private routeInfo: ActivatedRoute) {  }  ngOnInit() {    this.sellerId = this.routeInfo.snapshot.params['id'];  }}

seller-info.component.html

销售员ID是{ {sellerId}}

product-desc.component.html

这是一个牛叉的商品

product.component.html

这是是商品信息组件

商品Id是{ {productId}}

商品描述销售员信息

 子路由不仅仅可以嵌套两层 随着需求的复杂 可以无限往下嵌套

辅助路由

配置分为三步
{path: 'xxx',component: XxxComponent,outlet: 'aux'}{path: 'yyy',component: YxxComponent,outlet: 'aux'}
Xxx
Yyy

辅助路由案例 整体思路

在app 组件的模板上 再定义一个插座来显示聊天面板

单独开发一个聊天的插件,只显示在新定义的插座上

通过路由参数控制新插座是否显示聊天面板

ng g component chat

chat.component.html

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

home.component.html

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

product.component.html

这是是商品信息组件

商品Id是{ {productId}}

商品描述
销售员信息

product.component.css

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

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

主页商品详情开始聊天结束聊天

其中 primary:'home'  是为了 不论每次切换到chat组件时候 主页都显示home 

路由守卫

 使用场景

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

可以使用钩子来完成这些操作

有三种路由守卫

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

 

下面我们继续修改案例 只有当用户已经登录并拥有某些权限时才能进入产品路由

在app目录下 新建一个guard 文件夹 并新建一个 login.guard.ts

import {CanActivate} from '@angular/router';export class LoginGuard implements CanActivate {  canActivate() {    const loggedIn: boolean = Math.random() < 0.5;    if (!loggedIn) {      console.log('用户未登录');    }    return loggedIn;  }}

修改路由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';import {UnsavedGuard} from './guard/Unsaved.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 {}

这样就只有百分之50的概率进入商品路由了 

我们再新建一个 CanDeactivate:处理当前路由离开的情况。

guard 文件下 新建 Unsaved.guard.ts

import {CanDeactivate} from '@angular/router';import {ProductComponent} from '../product/product.component';export class UnsavedGuard implements CanDeactivate
{ canDeactivate(component: ProductComponent) { return window.confirm('你还没有保存,确定要离开么?'); }}

修改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';import {UnsavedGuard} from './guard/Unsaved.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],    canDeactivate: [UnsavedGuard],  },  {path: '**', component: Code404Component},];@NgModule({  imports: [RouterModule.forRoot(routes)],  exports: [RouterModule],  providers: [LoginGuard, UnsavedGuard],})export class AppRoutingModule {}

当从商品离开到别的组件的时候 就会弹出对话框

 

下面使用Resolve守卫

在guard文件下 创建product.resolve.ts

代码如下

///
import {ActivatedRouteSnapshot, Resolve, Router, RouterStateSnapshot} from '@angular/router';import {Product} from '../product/product.component';import {Observable} from 'rxjs';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, 'iPhoneX'); } else { this.router.navigate(['/home']); return undefined; } }}

product.component.html

这是是商品信息组件

商品Id是{ {productId}}

商品名称是{ {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 {  public productId: number;  public 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) {  }}

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';import {UnsavedGuard} from './guard/Unsaved.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: [LoginGuard, UnsavedGuard, ProductResolve],})export class AppRoutingModule {}

我们之前命名的1 2 3 还记得么

点击1 的时候 主页 点击2 的时候 进的是id 1 所以能进去 显示苹果7 点击3 的时候 进去的是id 2 所以显示失败  进入了主页

上一篇:【5】 【2】Auguar改造在线竞拍应用
下一篇:【5】 【1】Auguar开发一个在线竞拍项目

发表评论

最新留言

路过,博主的博客真漂亮。。
[***.116.15.85]2025年04月07日 17时04分01秒