首页 专题 H5案例 前端导航 UI框架

Angular4 开发实战:(10) 路由导航(Router)

作者:TG 日期: 2017-06-11 阅读: 3602
路由是Angular导航的关键。

<base href> 在设置路由之前,我们需要在app/index.html添加路由说明。 由于当前项目的根目录是app,所以添加如下代码:

<base href="/">

路由模块已经从Angular中分离出来,所以我们在使用时要导入:

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

现在可以来写一个简单的路由配置,我们将路由放置到一个模块中:

// app/modules/app-routing.module.ts   

import { NgModule } from '@angular/core';  

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

import {DemoComponentComponent} from '../demo/demo-component/demo-component.component';   


const routes: Routes = [   

  { path: 'demoComponent', component: DemoComponentComponent},   

  ...   

  { path: '**', component: DemoComponentComponent }  

];   


@NgModule({   

  imports: [   

    RouterModule.forRoot(routes)   

  ],   

  exports: [RouterModule]  

})  

export class AppRoutingModule { }

在上面的代码中,我们定义了一个路由数组,每一个都会把一个URL路径(path)映射到一个组件。 最后的**是路由通配符,当所有其上面的路由路径都不符合(包括无效路径)时,就会采取通配符路由。 注意:
  • 在特性模块中,应该使用RouterModule.forChild()
  • path不能以斜杠(/)开头
定义好路由模块后,我们还需要将其注册到主模块:

// app.module.ts   

...   

import { AppComponent } from './app.component';  

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


@NgModule({   

  ...   

  imports: [   

    ...   

    AppRoutingModule   

  ],   

  providers: [],   

  bootstrap: [AppComponent]  

})  

export class AppModule { }

有了路由导航,我们还需要一个容器来显示对应的组件内容:

<router-outlet></router-outlet>

添加如上代码后,当路由切换(路由模块中存在的路由)时,对应的组件会显示在其之后。 注:可以参考app/app.component.html。 注(来源官网):路由器使用先匹配者优先的策略来匹配路由,所以,具体路由应该放在通用路由的前面。在上面的配置中,带静态路径的路由被放在了前面,后面是空路径路由,因此它会作为默认路由。而通配符路由被放在最后面,这是因为它能匹配上每一个URL,因此应该只有在前面找不到其它能匹配的路由时才匹配它。 既然是路由导航,除了可以直接在浏览器的地址栏输入地址跳转外,我们更多时候需要一系列可以点击的链接元素(比如a,button):

<a routerLink="/demoComponent">创建组件</a>

由于导航路径是固定的,所以我们将一个字符串赋给routerLink。 注:a标签上的RouterLink指令让路由器得以控制这个a元素。 当然,如果我们需要更复杂的路由路径,我们可以使用链接参数数组:

[routerLink] = ['/demoComponent', 'id']   


[routerLink] = ['/demoComponent', { name: 'route', id: 123}]

一般情况下,我们会为当前激活的路径链接添加一些高亮效果,这时我们可以利用routerLinkActive属性:

<a routerLink="/demoComponent" routerLinkActive="active">创建组件</a>

它的值是一个以空格分割的CSS样式类列表。 还可以是一个CSS类数组:

[routerLinkActive]="['...']"

注(来源官网):RouterLinkActive指令会基于当前的RouterState对象来为激活的RouterLink切换CSS类。 这会一直沿着路由树往下进行级联处理,所以父路由链接和子路由链接可能会同时激活。 要改变这种行为,可以把[routerLinkActiveOptions]绑定到{exact: true}表达式。 如果使用了{ exact: true },那么只有在其URL与当前URL精确匹配时才会激活指定的RouterLink。 重定向 在路由配置中,我们还可以添加重定向参数:

{ path: '', redirectTo: '/demoComponent', pathMatch: 'full' }

注:重定向路由需要一个pathMatch属性,来告诉路由器如何用URL去匹配路由的路径,否则路由器就会报错。 路由参数 在配置路由时,我们还可以定义路由参数:

// app/modules/app-routing.module.ts   


{ path: 'demoRouter/:id', component: DemoRouterComponent}

比如输入http://localhost:4200/demoRouter/123,然后我们需要通过ActivatedRoute服务来获取这些路由参数:

// demo-router.component.ts   

import { Component, OnInit } from '@angular/core';  

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

...


export class DemoRouterComponent implements OnInit {    

  id: any;   

  constructor(private route: ActivatedRoute) {   

    this.route.params.subscribe(param => {   

      this.id = param['id'];   

    })   

  }      

...  

}

在上面的代码中,我们注入ActivatedRoute服务并定义了一个私有属性route,然后通过route.params属性来获取路由参数,ActivatedRoute.params是一个路由参数的可观察对象,所以我们要通过subscribe()方法来访问。 注:所有的路由参数或查询参数都是字符串。 子路由 子路由也是我们常用的,定义也很简单:

// app/modules/app-routing.module.ts   

import {DemoChildRouterComponent} from '../demo/demo-child-router/demo-child-router.component';   


const routes: Routes = [   

  ...   

  {   

    path: 'demoRouter2', component: DemoRouter2Component,   

    children: [{   

      path: 'child',   

      component: DemoChildRouterComponent   

    }]   

  }  

];

子路由组件:

// app/demo/demo-child-router.component.html   

<div class="box">   

  我是子路由  

</div>

前面说过我们要给路由添加视图容器,子路由也是一样,不过子路由的视图容器要放在另一个组件中:

// app/demo/demo-router2.component.html   

<div class="box">   

  <a routerLink="/demoRouter2/child">访问子路由</a>  

</div>   


<router-outlet></router-outlet>

当我们点击上面的链接时,你会看到浏览器地址栏变为:http://localhost:4200/demoRouter2/child,组件DemoChildRouterComponent中的模板就会显示出来。 路由动画 对于路由,我们还可以添加动画,但使用动画之前,我们要安装动画模块(Angular4后动画模块分离出来了):

npm install @angular/animations --save

然后在主模块app.module.ts中注册:

...   

import {BrowserAnimationsModule} from '@angular/platform-browser/animations';   


@NgModule({   

  declarations: [... ],   

  imports: [   

    ...   

    BrowserAnimationsModule   

  ],   

  providers: [],   

  bootstrap: [AppComponent]  

})  

export class AppModule { }

我们添加一个具有动画的子路由:

// app/modules/app-routing.module.ts   

import {DemoChildRouter2Component} from '../demo/demo-child-router/demo-child-router2.component';   


const routes: Routes = [   

  ...   

  {   

    path: 'demoRouter2', component: DemoRouter2Component,   

    children: [   

     ...   

     {   

       path: 'child2',   

       component: DemoChildRouter2Component   

    }]   

  }  

];

对于DemoChildRouter2Component组件,我们修改如下:

// demo/demo-child-router2.component.html   

import {Component, HostBinding, OnInit} from '@angular/core';  

import {animate, state, style, trigger, transition} from '@angular/animations';   


@Component({   

  selector: 'app-demo-child-router2',   

  templateUrl: './demo-child-router2.component.html',   

  styleUrls: ['./demo-child-router2.component.scss'],   

  animations: [    

    trigger('fadeInUpState', [   

      state('in', style({opacity: 1, transform: 'translate3d(0, 0, 0)'})),   

      transition('void => *', [   

        style({   

          opacity: 0,   

          transform: 'translate3d(0, 100%, 0)'   

        }), animate('.4s cubic-bezier(.25,.8,.25,1)')   

     ])   

    ])   

  ]  

})  


export class DemoChildRouter2Component implements OnInit {   

  @HostBinding('@fadeInUpState') fadeInUpState;   

  @HostBinding('style.display') display = 'block';   

  constructor() { }  

}

对于@HostBinding()是属性装饰器,用来给宿主设置属性。在这里我们将动画@fadeInUpState添加到宿主上,同时还将宿主的display的值设置为block。 注意:给宿主添加动画,一定要设置`display`的值,因为默认自定义元素的display是空字符串,CSS动画是不起作用的。 关于动画的更多细节,可以看《动画(Animation)》一章。 异步路由 随着项目越来越大,我们一般不会将所有组件都添加到主模块中,这时我们可以根据不同路由的;奥惰性加载不同的模块:

const routes: Routes = [   

  ...   

  {   

    path: 'demoRouter2',   

    component: DemoRouter2Component,   

    children: [   

      ...   

     {   

       path: 'loadModule',   

       loadChildren: 'app/demo/demo-router-load.module#RouterLoadModule',   

    }]   

  }  

];

当路由器导航到这个路由时,它会用loadChildren字符串来动态加载RouterLoadModule,然后把RouterLoadModule添加到当前的路由配置中, 最后,它把所请求的路由加载到目标DemoRouterLoadComponent组件中。 RouterLoadModule代码如下:

import {NgModule} from '@angular/core';  

import {CommonModule} from '@angular/common';  

import {DemoRouterLoadComponent} from './demo-router-load.component';  

import {DemoRouterLoadRougingModule} from './demo-router-load-routing.module';   


@NgModule({   

  imports: [CommonModule, DemoRouterLoadRougingModule],   

  declarations: [DemoRouterLoadComponent]  

})   


export class RouterLoadModule {}

仔细看的话,你会发现一个新的子路由模块DemoRouterLoadRougingModule,它是用来加载异步路由配置的:

// demo-router-load-routing.module.ts   

import {NgModule} from '@angular/core';  

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

import {DemoRouterLoadComponent} from './demo-router-load.component';   


const routes: Routes = [   

  {   

    path: '',   

    component: DemoRouterLoadComponent   

  }  

]  


@NgModule({   

  imports: [RouterModule.forChild(routes)],   

  exports: [RouterModule]  

})   


export class DemoRouterLoadRougingModule {}

使用:

// demo-router2.component.html   

<a routerLink="/demoRouter2/loadModule">访问异步路由</a>

当你点击上面的链接时,你可以打开控制台看看Network看看会多了一个加载文件: 注:惰性加载和重新配置工作只会发生一次,也就是在该路由首次被请求时。在后续的请求中,该模块和路由都是立即可用的。

如发现任何问题或有好的建议,欢迎在下方评论留言。

关注”全栈技术杂货铺“

全栈技术杂货铺