zoukankan      html  css  js  c++  java
  • ng-book札记——路由

    路由的作用是分隔应用为不同的区块,每个区块基于匹配当前URL的规则。

    路由可以分为服务端与客户端两种,服务端以Express.js为例:

    var express = require('express');
    var router = express.Router();
    
    // define the about route
    router.get('/about', function(req, res) {
      res.send('About us');
    });
    

    服务端接收请求并路由至一个控制器(controller),控制器执行指定的操作(action)。

    客户端的路由在概念上与服务端相似,其好处是不需要每次URL地址变化都将路由请求发送至服务端。

    客户端路由有两种实现方式:使用传统的锚(anchor)标签与HTML5客户端路由。第一种方式也被称为hash-based路由,URL的形式如这般:http://something/#/about。第二种依赖HTML5的history.pushState方法,缺点是老旧的浏览器不支持这种方式,以及服务器也必须支持基于HTML5的路由。Angular官方推荐的是后者。

    使用Angular路由的方法,首先要导入相关类库:

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

    再配置路由规则:

    const routes: Routes = [
      // basic routes
      { path: '', redirectTo: 'home', pathMatch: 'full' },
      { path: 'home', component: HomeComponent },
      { path: 'about', component: AboutComponent },
      { path: 'contact', component: ContactComponent },
      { path: 'contactus', redirectTo: 'contact' }
    ]
    

    path指定路由所要处理的URL,component绑定相关的组件,redirectTo重定向至已知的路由。

    最后在NgModule中引入RouterModule模块及预设的路由:

    imports: [
      BrowserModule,
      FormsModule,
      HttpModule,
      RouterModule.forRoot(routes), // <-- routes
    
      // added this for our child module
      ProductsModule
    ]
    

    Angular默认的路由策略是PathLocationStrategy,即基于HTML5的路由。如果想使用HashLocationStrategy,需要在代码里额外申明。

    providers: [
      { provide: LocationStrategy, useClass: HashLocationStrategy }
    ]
    

    路由上可以带参数,通过/route/:param的形式。不过这种情况下需要导入ActivatedRoute。

    import { ActivatedRoute } from '@angular/router';
    
    const routes: Routes = [
      { path: 'product/:id', component: ProductComponent }
    ];
    
    export class ProductComponent {
      id: string;
    
      constructor(private route: ActivatedRoute) {
        route.params.subscribe(params => { this.id = params['id']; });
      }
    }
    

    想在页面中添加跳转链接的话,可以使用[routerLink]指令:

    <div class="page-header">
      <div class="container">
      <h1>Router Sample</h1>
      <div class="navLinks">
        <a [routerLink]="['/home']">Home</a>
        <a [routerLink]="['/about']">About Us</a>
        <a [routerLink]="['/contact']">Contact Us</a>
        |
        <a [routerLink]="['/products']">Products</a>
        <a [routerLink]="['/login']">Login</a>
        <a [routerLink]="['/protected']">Protected</a>
        </div>
      </div>
    </div>
    

    而如果想要用模板页面的话,则需要指令:

    <div id="content">
      <div class="container">
        <router-outlet></router-outlet>
      </div>
    </div>
    

    页面中的router-outlet元素即是每个路由绑定的组件所渲染内容的位置。

    复杂的页面可能还会需要用到嵌套路由:

    const routes: Routes = [
      //nested
      { path: 'products', 
        component: ProductsComponent,
        chilren: [
         { path: '', redirectTo: 'main', pathMatch: 'full' },
         { path: 'main', component: MainComponent },
         { path: 'more-info', component: MoreInfoComponent },
         { path: ':id', component: ProductComponent },
        ] 
      }
    ]
    

    路由的建立是经由相对路径来构成,所以需要有配置其基础路径位置的地方,一般这个配置会放在index.html页面的base元素中。

    <!doctype html>
    <html>
    <head>
      <meta charset="utf-8">
      <title>Routing</title>
      <base href="/">
    
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <link rel="icon" type="image/x-icon" href="favicon.ico">
    </head>
    <body>
      <app-root>Loading...</app-root>
    </body>
    </html>
    

    最常见的写法就是<base href="/">

    同时还可以在NgModule中以代码实现,两者效果等效:

    providers: [
      { provide: APP_BASE_HREF, useValue: '/' } // <--- this right here
    ]
    

    切换路由时可能会有要求额外的处理工作,比如认证。这种场景下,路由的构子可以派上用处。

    import { Injectable } from '@angular/core';
    
    @Injectable()
    export class AuthService {
      login(user: string, password: string): boolean {
        if (user === 'user' && password === 'password') {
          localStorage.setItem('username', user);
          return true;
        }
    
        return false;
      }
      
      logout(): any {
        localStorage.removeItem('username');
      }
    
      getUser(): any {
        return localStorage.getItem('username');
      }
    
      isLoggedIn(): boolean {
        return this.getUser() !== null;
      }
    }  
    
    export const AUTH_PROVIDERS: Array<any> = [
      { provide: AuthService, useClass: AuthService }
    ];
    
    import { Injectable } from '@angular/core';
    import {
      CanActivate,
      ActivatedRouteSnapshot,
      RouterStateSnapshot
    } from '@angular/router';
    import { Observable } from 'rxjs/Observable';
    import { AuthService } from './auth.service';
    
    @Injectable()
    export class LoggedInGuard implements CanActivate {
      constructor(private authService: AuthService) {}
    
      canActivate(
        next: ActivatedRouteSnapshot,
        state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
        const isLoggedIn = this.authService.isLoggedIn();
        console.log('canActivate', isLoggedIn);
        return isLoggedIn;
      }
    }
    
    import { AUTH_PROVIDERS } from './auth.service';
    import { LoggedInGuard } from './logged-in.guard';
    
    const routes: Routes = [
     {
       path: 'protected',
       component: ProtectedComponent,
       canActivate: [ LoggedInGuard ]
     },
    ];
    

    上述例子中,当路由至'protected'地址时,'LoggedInGuard'处理类会进入路由调用环路,依据是否已登陆这一信息来决定此次路由是否有效。

  • 相关阅读:
    mysql命令大全(转发)
    算法大神学习之路
    MYSQL之explain的作用与相关知识
    FastDFS(分布式存储系统)+nginx web 服务器
    获取用户浏览历史记录(django_redis)
    用户登陆装饰器和页面跳转(包含mixin的使用)
    .NET 方法回调
    asp.net viewstate 数据过大 导致错误
    asp.net viewstate 数据大导致错误
    软件测试 Record
  • 原文地址:https://www.cnblogs.com/kenwoo/p/8906041.html
Copyright © 2011-2022 走看看