ng2 路由

https://angular.cn/guide/router
激活路由参数
添加路由动画
懒加载路由

创建模块来放置模块相关的组件,比如购买就放置购买相关的组件,和路由 创建模块路由注意 app.module.ts 中import导入的顺序, AppRoutingModule 是最后一个
考虑让每个特性模块都有自己的路由配置文件

在 AppRoutingModule 中,使用静态的 RouterModule.forRoot方法来注册路由和全应用级服务提供商
在特性模块中,你要改用forChild静态方法

ng generate module app-routing --flat --module=app

$ ng g module --help
--module=app // 把它注册到 App.module 的 imports 数组中
 --flat    // 如果为true,则在当前项目根目录的顶级创建新文件
--routing //  如果为true,则创建路由模块。
--routing-scope    // 新路由模块的范围。

配置 app-routing.module.ts

const routes: Routes = [
  {
    path: "",
    component: DashboardComponent,
    children: [
      { path: "home", component: HomeComponent },
      {
        path: "about",
        component: AboutComponent,
      },
      { path: "", redirectTo: "home", pathMatch: "full" },
    ],
  },

  // 注册404页面
  {path: 'not-found',  component: NotFoundComponent },
  // 当没有匹配到任何页面,跳转到404
  {path: '**', redirectTo: '/not-found', pathMatch: 'full'},
];

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

app/app.component.html

<router-outlet></router-outlet>

app/pages/dashboard/dashboard.component.html

<nav mat-tab-nav-bar backgroundColor="primary" color='accent'>
  <a
    mat-tab-link
    *ngFor="let link of navLinks"
    [routerLink]="link.path"
    routerLinkActive
    #rla="routerLinkActive"
    [active]="rla.isActive"
  >
    {{ link.label }}
  </a>
</nav>
<router-outlet></router-outlet>

// ts 
  navLinks = [
    {
      path: "/home",
      label: "home",
    },

    {
      path: "/about",
      label: "about",
    },
    {
      path: "/welcome",
      label: "welcome",
    },
  ];

app.module.ts 中注册 router(一般cli已经帮你注册好了)

import { AppRoutingModule } from './app-routing.module'; // 
@NgModule({
  imports: [ AppRoutingModule ]
})
export class AppModule { }

动态路由

const routers: Routes = [
  { path: 'login/:id', component: LoginComponent } // 加上:id 就是动态路由了
];

home.component.html

<a routerLink="/login/a">to login page</a>
<a [routerLink]="['/login', 'a']">to login page</a>

从路由参数中提取 id

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

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


@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
  constructor(
    private route: ActivatedRoute,
    private localtion: Location
  ) { }
  ngOnInit() {
    console.log( this.route.snapshot.paramMap.get('id') ); // 获取id参数 => a
  }
}

事件激活路由 docs

import { Router } from '@angular/router';
constructor( private router: Router ) {}
  toTest() {
    this.router.navigate(['/test', {id: Math.random(), name: 'test.'}]); // route.snapshot.paramMap.get('id')  获取参数
  }

 // 触发动态路由 
  toTest() {
    this.router.navigate(['/test', 233]);
  }

路由守卫 文档

守卫返回一个值,以控制路由器的行为

  • true,导航过程会继续
  • false,导航过程就会终止,且用户留在原地
  • UrlTree,则取消当前的导航,并且开始导航到返回的这个 UrlTree

守卫可以用同步的方式返回一个布尔值。但在很多情况下都是异步操作。因此可以返回 Observable 或 Promise,并且路由器会等待这个可观察对象被解析为 true 或 false。

路由器可以支持多种守卫接口:

  • 用CanActivate来处理导航到某路由的情况。假如绑定到"home"守卫返回false的情况,直接访问home会被拦截,直接访问home/child也会被拦截 canActivate只会在父组件尚未创建时执行
  • 用CanActivateChild来处理导航到某子路由的情况。在子路由中导航时会被执行
  • 用CanDeactivate来处理从当前路由离开的情况.
  • 用Resolve在路由激活之前获取路由数据。
  • 用CanLoad来处理异步导航到某特性模块的情况。

canDeactivate

修改了数据情况,询问用户是否确认离开

import { Injectable } from "@angular/core";
import { ActivatedRouteSnapshot, RouterStateSnapshot } from "@angular/router";
import { Observable } from "rxjs";
import { CanDeactivate } from "@angular/router";
import { HomeComponent } from "./home/home.component";

@Injectable({
  providedIn: "root",
})
export class CanDeactivateGuard implements CanDeactivate<HomeComponent> {
  canDeactivate(
    component: HomeComponent, // 获取组件实例
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot,
  ): Observable<boolean> | Promise<boolean> | boolean {
    if (component.username === "ajanuw") {
      return true;
    }
    return window.confirm("您确定放弃修改,并退出页面吗?");
  }
}

canActivate

权限拦截

import { Injectable } from "@angular/core";
import {
  CanActivate,
  ActivatedRouteSnapshot,
  RouterStateSnapshot,
  Router,
} from "@angular/router";
import { Observable } from "rxjs";

@Injectable({
  providedIn: "root",
})
export class AuthGuard implements CanActivate {
  constructor(private readonly router: Router) {}

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot,
  ): Observable<boolean> | Promise<boolean> | boolean {
    let isLogin = false; // 硬編碼

    // 验证登陆后通过,否则从定向
    if (isLogin) return true;

    this.router.navigate(["/"]);
    return false;
  }
}

发送对象

    // to
    this.router.navigate(['/screen2'], {
      state: {
        a: 'hello',
        b: 'NG',
      },
    });

  // newPage
export class Screen2Component implements OnInit {
  constructor(
    private router: Router,
  ) {
    const navigation = this.router.getCurrentNavigation();
    const state = navigation.extras.state as {
      a: string;
      b: string;
    };
    console.log(state);
  }

  ngOnInit() {}
}

懒加载路由(模块)

通常类似admin这样的模块并不是谁都能访问的.

快速创建admin模块

λ ng g module admin --module app --route admin

上面的命令在src/admin下创建后,会自动在AppRoutingModule里面注册,如:

import { NgModule, Injectable } from "@angular/core";
import { Routes, RouterModule, Resolve } from "@angular/router";
import { HomeComponent } from "./home/home.component";
import { AboutComponent } from "./about/about.component";

@Injectable({
  providedIn: "root"
})
export class ThrottleService implements Resolve<any> {
  resolve() {
    return new Promise(resolve => setTimeout(resolve, 2000));
  }
}

const routes: Routes = [
  {
    path: "",
    component: HomeComponent,
    pathMatch: "full"
  },
  {
    path: "about",
    component: AboutComponent
  },
  {
    path: "admin",
    loadChildren: () => import("./admin/admin.module").then(m => m.AdminModule),
    resolve: {
       // 引入了延迟,以便您可以看到微调器在起作用
       // resolve 通常是为了在导航到路由页面前,提前获取数据
      ThrottleService: ThrottleService
    }
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule {}
<router-outlet>
  <span class="loader" *ngIf="loading">loading...</span>
</router-outlet>
import {
  Router,
  RouterEvent,
  NavigationStart,
  NavigationEnd
} from "@angular/router";

export class DashboardComponent implements OnInit {
  loading = false;
  constructor(private readonly router: Router) {
    this.router.events.subscribe((event: RouterEvent): void => {
      if (event instanceof NavigationStart) {
        this.loading = true;
      } else if (event instanceof NavigationEnd) {
        this.loading = false;
      }
    });
  }
}

预加载延迟路由

延迟路由适合初始页面加载,但它会减慢导航速度

  1. 使用PreloadAllModules, 它会预先加载所有延迟加载的路由
RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })
  1. 自定义预加载策略, 只预加载那些 data.preload 标志为 true 的路由
import { NgModule, Injectable } from "@angular/core";
import {
  Routes,
  RouterModule,
  Resolve,
  PreloadAllModules,
  PreloadingStrategy,
  Route
} from "@angular/router";
import { HomeComponent } from "./home/home.component";
import { AboutComponent } from "./about/about.component";
import { Observable, of } from "rxjs";

@Injectable({
  providedIn: "root"
})
export class SelectivePreloadingStrategyService implements PreloadingStrategy {
  preloadedModules: string[] = [];
  preload(route: Route, load: () => Observable<any>): Observable<any> {
    if (route.data && route.data["preload"]) {
      this.preloadedModules.push(route.path);
      return load();
    } else {
      return of(null);
    }
  }
}

const routes: Routes = [
   ...
  {
    path: "admin",
    loadChildren: () => import("./admin/admin.module").then(m => m.AdminModule),
    // 将preload改为true,将自动加载
    data: { preload: false }
  }
];

@NgModule({
  imports: [
    RouterModule.forRoot(routes, {
      // 使用实现了preload的服务
      preloadingStrategy: SelectivePreloadingStrategyService
    })
  ],
  providers: [SelectivePreloadingStrategyService],
  exports: [RouterModule]
})
export class AppRoutingModule {}
  1. 使用 ngx-quicklink 如果延迟路由的连接出现在页面上,就开始预加载
npm install --save ngx-quicklink

可以将 QuicklinkModule 导入 SharedModule 中

import {QuicklinkStrategy, QuicklinkModule} from 'ngx-quicklink';
…

@NgModule({
  …
  imports: [
    …
    QuicklinkModule,
    RouterModule.forRoot([…], {
      preloadingStrategy: QuicklinkStrategy
    })
  ],
  …
})
export class AppModule {}

如果要忽略掉ngx-quicklink

  {
    path: 'contact',
    loadChildren: import(() => './contact/contact.module').then(m => m.ContactModule),
    data: {
       // 设置为false
      preload: false
    }
  }
  1. 使用guess.js 来预测用户会进入那些页面,在进行预加载 guess&angular
posted @ 2018-03-15 10:44  Ajanuw  阅读(66)  评论(0)    收藏  举报