Angular学习笔记(四)Angular Router 导航

学习路由基本知识
学习子路由、保护路由、辅助路由等

一、创建路由项目

使用 ng new xxx --routing来创建一个带有angular官方路由的项目

加routing参数,会新增一个app-routing.module.ts 文件

二、路由基础知识

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

路由配置文件

app-routing.module.ts中配置路由

const routes: Routes = [
    { path: 'product', component: ProductComponent },
    { path: '', component: HomeComponent }
]
// 注意路径中不能加 / 号,如path:'/product'是会报错的

在html中写入标签<router-outlet></router-outlet>来展示相关组件

路由通用配置

{ path: '**', component:Code404Component }
// 路由路径的通用配置,注意不可以写在最前面,否则路由会优先匹配

routerLink的使用

<a [routerLink]="['/]">home</a>
<a [routerLink]="['/product']">产品</a>
<router-outlet></router-outlet>
// 点击a标签,导航到相关路径

Router路由对象导航到指定路由

<input type="button" value="产品" (click)="toProduct"/>
// tips: 这里的click是angular的事件绑定

export class Appcomponent = {
    constructor(private router: Router){
        // 这里可以拿到router对象
    }
    toProduct(){
        // 导航到指定路由
        this.router.navigate(['/product'])
    }
}

在路由中传递数据(ActivatedRoute)

1.在查询参数中传递数据
 /product?id=1&name=2 => ActivatedRoute.queryParams[id]
2.在路由路径中传递数据
{ path: /product/:id } => /product/1 => ActivatedRoute.params[id]
// 注意这里不是queryParams,而是params
3.在路由配置中传递数据
{ path: /product, component:ProductComponent, data:[{isProd}]} => ActivatedRoute.data[0][isProd]

在查询参数中传递数据

 <a [routerLink]="['/product']" [queryParams="{id: 1}"]>产品</a>
// 在url中可以看到product?id=1

export class ProductComponent implements OnInit {
    private productId: number;
    constructor(private routeInfo: ActivatedRoute){
        // 这里可以拿到routeInfo对象
    }
    ngOnInit(){
        this.productId = this.routeInfo.snapshot.queryParams["id"];
    }
}

// 这样就可以在product.component.html中展示拿到的productId 的值
<p>{{productId}}</p>

在路由路径中传递数据

// 在路由配置中修改path属性,使其可以携带参数
const routes: Routes = [
    { path: 'product/:id', component: ProductComponent },
]
// 在html中修改如下
 <a [routerLink]="['/product',666]">产品</a>
// 这样路径就变为product/666

// 稍微改动ts文件,使html中可以得到路径传递数据方式的productId 的值
export class ProductComponent implements OnInit {
    private productId: number;
    constructor(private routeInfo: ActivatedRoute){
        // 这里可以拿到routeInfo对象
    }
    ngOnInit(){
        this.productId = this.routeInfo.snapshot.params["id"];  // 这里修改为params就行了
    }
}
// 然后在html中可以显示出productId 的值了
<p>{{productId}}</p>

tips:关于参数快照snapshot和参数订阅

// 你可以看到上面的代码中,routeInfo对象有一个snapshot的属性,
这就是参数快照,但是只能被调用一次(组件被创建时,构造函数只能初始化一次),
为了解决因此导致的productId值不会被改变,我们可以使用参数订阅来搞定它

// 我们来修改这段代码
export class ProductComponent implements OnInit {
    private productId: number;
    constructor(private routeInfo: ActivatedRoute){
        // 这里可以拿到routeInfo对象
    }
    ngOnInit(){
        // 修改这里
        this.routeInfo.params.subscribe((params: Params) => this.productId = params["id"])
        //subscribe就是参数订阅,实际上是RxJs中的语法,在后面我们会讲到。
    }
}

重定向路由

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

// 我们修改路由配置
const routes: Routes = [
    { path: '', redirectTo:'/home', pathMatch: 'full' },
    { path: '/home', component: HomeComponent }
]
// 你可以看到在第一行中我加了一条新的路径,它告诉angular当我访问空路径时,把当前路由重定向到home的路径上,是不是很简单

子路由

{ path: '/home', component: HomeComponent } // 这是一个普通的路由配置

// 当我想配置子路由时
{ path: '/home', component: HomeComponent,
    children: [
        {
            path: '',component: XxxComponent
        },
        {
            path: '/yyy',component: YyyComponent
        }
    ]
 }

// html中
在相关模板加入<router-outlet></router-outlet>就能展示了
// 但是有点小问题需要注意,在html中,如果你想用a链接跳转到相关子路由,如''这个路径
<a [routerLink]="['./']"></a> 
// 这样才能访问子路由中空路径的组件,如果是'/',则会跳转到主路由中的空路径而不是当前路由的子路由

辅助路由

// 辅助主路由,可以保持主路由变化时自身路由不变

// html中
<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> // 主插座,导航到home组件,辅助路由显示xxx组件,下同
<a [routerLink]="['/product', {outlets: {aux: 'yyy'}}]">Yyy</a>

路由守卫(保护路由)

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

// 三种路由守卫
1.CanActivate  处理导航到某路由的情况
2.CanDeactivate  处理从当前路由离开的情况
3.Resolve  在路由激活之前获取路由数据
1.CanActivate
// 我们在src/app文件夹下新建一个guard文件夹,在guard文件夹下新建login.guard.ts文件,用来模拟用户未登录或者登录后路由守卫可以做的事

// 在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("用户未登录")
    }else {
      console.log("用户已登录")
    }
    return loggedIn;
  }
}

// 路由配置中
const routes: Routes = [
  {path: 'product',component: ProductComponent, canActivate: [LoginGuard]}, // 比如我们要访问产品组件,需要判断登录状态
];

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

// 这样,在组件中点击你写好的按钮(导航到'product',你可以看到随机打印的登录状态,canActivate根据不同状态来处理不同逻辑)
2.CanDeactivate
// 我们在guard文件夹下新建unsaved.guard.ts文件

// 在unsaved.guard.ts中写
import {CanDeactivate} from "@angular/router";
import {ProductComponent} from "../product/product.component";

export class UnsavedGuard implements CanDeactivate<ProductComponent> {
  canDeactivate(component: ProductComponent){
    return window.confirm("你还没有保存信息,确定离开当前页面么?")
  }
}

// 路由配置中
const routes: Routes = [
  {path: 'product',component: ProductComponent, canActivate: [LoginGuard],canDeactivate: [UnsavedGuard]}, 
];

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

// 这样,当我们离开product路径时,CanDeactivate路由守卫会弹出框提示你是否离开当前页面
3.Resolve
// 我们在guard文件夹下新建product.resolve.ts文件

// 在product.resolve.ts中写
import {ActivatedRouteSnapshot, Resolve, Router, RouterStateSnapshot} from "@angular/router";
import {Product} from "../product/product.component";
import {Observable} from "rxjs/Observable";
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"); // 如果productId 为1,则商品ID为1,商品名称为7
    }else {
      this.router.navigate(['/home']); // 如果productId 不是1,则跳转到‘’/home'
      return undefined;
    }
  }
}

// 路由配置中
const routes: Routes = [
  {path: 'product',component: ProductComponent, canActivate: [LoginGuard],canDeactivate: [UnsavedGuard],resolve: {
  product: ProductResolve
}}, 
];

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

// 这样,我们在访问/product时,可以让Resolve带着路由信息访问该路径

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容