Angular学习笔记02——路由

449 阅读6分钟

###1、路由基础

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

#####使用 1、创建带路由的angular项目
ng new router --routing项目名称为router,通过routing参数,使创建出来的项目带用路由的对应文件。
这样创建出的项目比不带routing多出app-routing.module.ts脚本文件,在该文件中可以定义Routes:

import { ProductComponent } from './product/product.component';

//定义Routes,指定不同的path指向不同的组件
const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'product', component: ProductComponent },
  { path: '**', component: Code404Component }
];

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

同时可以看到在app.component.html中:

<a [routerLink]="['/']">主页</a>
<a [routerLink]="['/product']">商品详情</a>
<input type="button" value="商品详情" (click)="toProductDetails()">
<router-outlet></router-outlet>

通过routerLink去引用前面定义的routes,实现页面的变换。变换的位置由html文件中的<router-outlet></router-outlet>决定。

除了这种方法去调用路由之外,也可以通过脚本方法的方式去定义和调用路由,在app.component.ts文件中定义如下:

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

}

配合html中按钮的点击事件,也可以实现路由的功能,使用的是router对象。 ###2、在路由时传递参数 a、在查询参数中传递 /product?id=1&name=2 => ActivatedRoute.queryParams[id]
代码示例:

<a [routerLink]="['/']">主页</a>
<a [routerLink]="['/product']" [queryParams]="{id:1}">商品详情</a>
<input type="button" value="商品详情" (click)="toProductDetails()">
<router-outlet></router-outlet>

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;
  // 在构造函数里声明ActivatedRoute对象,在初始化方法里面通过ActivatedRoute对象获取查询参数
  constructor(private routerinfo: ActivatedRoute) {
  }

  ngOnInit() {
    this.productId = this.routerinfo.snapshot.queryParams['id'];
  }
}

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

b、在路由路径中传递 {path:/product/:id} => /product/1 => ActivatedRoute.queryParams[id]
代码示例:

<a [routerLink]="['/']">主页</a>
<!-- <a [routerLink]="['/product']" [queryParams]="{id:1}">商品详情</a> -->
<a [routerLink]="['/product',1]">商品详情</a>
<input type="button" value="商品详情" (click)="toProductDetails()">
<router-outlet></router-outlet>

import { ProductComponent } from './product/product.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 { }

import { Params } from '@angular/router/src/shared';

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

  private productId: number;

  constructor(private routerinfo: ActivatedRoute) {

  }


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

}

c、在路由配置中传递

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

代码示例如下:

<a [routerLink]="['/']">主页</a>
<!-- <a [routerLink]="['/product']" [queryParams]="{id:1}">商品详情</a> -->
<!-- <a [routerLink]="['/product',1]">商品详情</a> -->
<a [routerLink]="['/product']">商品详情</a>
<input type="button" value="商品详情" (click)="toProductDetails()">
<router-outlet></router-outlet>	

import { ProductComponent } from './product/product.component';

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

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

import { Params } from '@angular/router/src/shared';

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

  private productId: number;

  constructor(private routerinfo: ActivatedRoute) {

  }


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

}

####参数快照和参数订阅

  ngOnInit() {
	//订阅
    // this.routerinfo.params.subscribe((params: Params) => this.productId = params['id']);
	//快照
    // this.productId = this.routerinfo.snapshot.queryParams['id'];
    // this.productId = this.routerinfo.snapshot.params['id'];
    this.productId = this.routerinfo.snapshot.data[0]['id'];
  }

###3、重定向路由 语法:{path:'xx',redirectTo: '/xxx', pathMatch: 'full' }
代码示例:

import { ProductComponent } from './product/product.component';

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

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

###4、子路由 语法:

{path:'home',component:HomeComponent
	children:[
		{
			path:'',component:xxxComponent
		},
		{
			path:'/yyy',component:yyyComponent
		}
	]
}

如果路由这样配置的话,访问路径是/home的时候,app的html中的<router-outlet>标签会展示HomeComponent组件,HomeComponent组件的<router-outlet>会展示xxxComponent组件。
当访问路径是/home/yyy的时候,app的html中的<router-outlet>标签会展示HomeComponent组件,HomeComponent组件的<router-outlet>会展示yyyC omponent组件。 ###5、辅助路由 语法:

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

{path:'xxx',component:xxxComponent.outlet:'other'}
{path:'yyy',component:yyyComponent.outlet:'other'}

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

也可以通过下面的方法调用来实现主路由同时变化,让主路由跳转到home路径:

<a [routerLink]="['/product',{primary:'home',outlets:{other:'yyy'}}]">yyy</a>

###6、路由守卫 对路由的访问进行控制,增加额外的业务逻辑判断功能。可以用于如下场景:
1、只有当用户已经登录并拥有某些权限时才能进入某些路由。
2、一个多个表单组成的向导,如注册流程,用户只有在当前路由的组件中完成了满足条件的信息才可以导航到下个路由。
3、当用户未执行保存操作而试图离开当前导航时提醒用户。
代码实现如下:

import { ChildrenOutletContexts } from '@angular/router/src/router_outlet_context';
import { OutGuard } from './guard/out.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: 'sellerInfo/:id', component: SellerInfoComponent }
    ], 
	//在路由配置中增加如下配置,类似于方法拦截器,canActivate是进入当前组件需要执行的守卫,canDeactivate是离开当前组件需要执行的方法。
	canActivate: [LoginGuard], 
	canDeactivate: [OutGuard]
  },
  // { path: 'product', component: ProductComponent, data: [{ id: 3 }] },
  { path: '**', component: Code404Component }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
  //守卫类需要在这里进行注册
  providers: [LoginGuard, OutGuard]
})
export class AppRoutingModule { }

守卫类的实现:
import { CanActivate } from '@angular/router'; //需要实现接口并实现接口定义的方法 export class LoginGuard implements CanActivate { canActivate() {

        // tslint:disable-next-line:prefer-const
        let loginIn: boolean = Math.random() < 0.5;

        if (!loginIn) {
            console.log('用户未登录!');
        }
        return loginIn;

    }

}

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

export class OutGuard implements CanDeactivate<ProductComponent> {
    canDeactivate(component: ProductComponent) {
        return window.confirm('是否确定离开本页面?');
    }

}

###7、resolve守卫 作用:在路由跳转之前提前加载数据或其他操作,提高用户体验。
代码实现:

import { OutGuard } from './guard/out.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: 'sellerInfo/:id', component: SellerInfoComponent }
    ],
    // canActivate: [LoginGuard],
    // canDeactivate: [OutGuard]
	//配置resolve,声明需要传到下一个组件的参数
    resolve: {
      product: ProductResolve
    }
  },
  // { path: 'product', component: ProductComponent, data: [{ id: 3 }] },
  { path: '**', component: Code404Component }
];

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

import { Product } from '../product/product.component';

@Injectable()//需要注册当前类,实现内部依赖注入Router对象
export class ProductResolve implements Resolve<Product> {
    constructor(private router: Router) { }
    resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Product | Observable<Product> | Promise<Product> {


        // tslint:disable-next-line:prefer-const
        let productId: number = route.params['id'];

        // tslint:disable-next-line:triple-equals
        if (productId == 1) {
            return new Product(1, '商品1');
        } else {
            this.router.navigate(['/home']);
        }
    }

}

import { Params } from '@angular/router/src/shared';

@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 routerinfo: ActivatedRoute) {

  }
  ngOnInit() {
    // this.routerinfo.params.subscribe((params: Params) => this.productId = params['id']);
    // this.productId = this.routerinfo.snapshot.queryParams['id'];
    // this.productId = this.routerinfo.snapshot.params['id'];
    // this.productId = this.routerinfo.snapshot.data[0]['id'];
	//获取具体参数
    this.routerinfo.data.subscribe((data: { product: Product }) => {
      this.productId = data.product.id;
      this.productName = data.product.name;
    });
  }

}
//实现product实体类
export class Product {
  constructor(public id: number, public name: String) { }
}