迈向angularjs2系列(6):路由机制

目录
1.angular-seed的路由
2.路由机制的探索
3.懒加载

一:angular-seed的路由

step1:安装种子项目

  

    $ git clone --depth 1 https://github.com/AngularClass/angular2-seed.git  developer-hub

         //git cmd进入到项目目录后运行此命令,我的项目的名称为developer-hub

    $  cd   developer-hub     //webstorm命令行进入项目目录

    $  npm install    //json文件修改好之后再运行install命令

    $  npm start

注意:
在npm install之前要修改tsconfig.json,
"compilerOptions": {
      "lib": ["es6", "dom"]
}
打开localhost:3000就可以看到种子项目的"hello"界面了。
step2:
分析一下种子项目的目录结构,并且改一改看能不能修改成功。
看顶级目录:
● .awcache是缓存

● dist放最后生产用的文件

● node-modules放node模块

● src 源代码

● .gitignore文件是git用于配置不需要加入版本管理的文件,比如最后两行是

.awcache
.DS_Store

LICENSE,我的是

Apache License
Version 2.0, January 2004

package.json

{
  "name": "angular2-seed",
  "version": "0.0.0",
  "description": "A simple Angular 2 Seed featuring Angular 2 and Webpack 2",
  "author": "PatrickJS <github@gdi2290.com>",//作者
  "main": "index.js",
   //主入口
  "files": [
    "dist",
    "src"
  ],
  "scripts": {//npm脚本
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "npm run server:dev",
    "start:hmr": "npm run server:dev -- --env.HMR",
    "server:dev": "webpack-dev-server --env.ENV development",
    "debug:start": "node-nightly --inspect --debug-brk node_modules/webpack-dev-server/bin/webpack-dev-server.js --env.ENV development",
    "debug:build": "node-nightly --inspect --debug-brk node_modules/webpack/bin/webpack.js --env.ENV development",
    "predll": "rimraf dist/dll/*.*",
    "dll": "webpack --config webpack.dll.ts --env.ENV development",
    "prebuild": "rimraf dist/*.*",
    "build": "webpack --env.ENV development",
    "build:hmr": "npm run build -- --env.HMR"
  },
  "dependencies": {
    //项目
    "@angular/common": "~2.0.1",
    "@angular/compiler": "~2.0.1",
    "@angular/compiler-cli": "~0.6.3",
    "@angular/core": "~2.0.1",
    "@angular/http": "~2.0.1",
    "@angular/forms": "~2.0.1",
    "@angular/router": "~3.0.1",
    "@angular/platform-browser": "~2.0.1",
    "@angular/platform-browser-dynamic": "~2.0.1",
    "@angular/platform-server": "~2.0.1",
    "@angularclass/conventions-loader": "^1.0.12",
    "@angularclass/form-validators": "^1.0.11",
    "@angularclass/resolve-angular-routes": "^1.0.8",
    "@angularclass/hmr-loader": "~3.0.1",
    "@angularclass/hmr": "~1.2.0",
    "core-js": "^2.4.1",
    "rxjs": "5.0.0-beta.12",
    "zone.js": "~0.6.25"
  },
  "devDependencies": {
    //dev项目依赖
    "@types/core-js": "^0.9.28",
    "@types/node": "^4.0.30",
    "assets-webpack-plugin": "^3.4.0",
    "awesome-typescript-loader": "^2.2.1",
    "cross-spawn": "^4.0.0",
    "es6-promise": "^3.1.2",
    "es6-shim": "^0.35.0",
    "ie-shim": "^0.1.0",
    "ignore-loader": "^0.1.1",
    "json-loader": "^0.5.4",
    "raw-loader": "^0.5.1",
    "rimraf": "^2.5.4",
    "string-replace-loader": "github:gdi2290/string-replace-loader",
    "to-string-loader": "^1.1.4",
    "ts-helpers": "github:gdi2290/ts-helpers",
    "ts-loader": "^0.8.2",
    "ts-node": "^1.2.2",
    "typescript": "2.0.2",
    "webpack": "~2.1.0-beta.25",
    "webpack-dev-middleware": "^1.6.1",
    "webpack-dev-server": "^2.1.0-beta.8"
  },
  "license": "Apache-2.0",
    //许可证
  "bugs": {
    "url": "https://github.com/gdi2290/angular2-webpack2-starter/issues"
  },
  "homepage": "https://github.com/gdi2290/angular2-webpack2-starter#readme",
   //主页
  "repository": {
   //仓库
    "type": "git",
    "url": "git+https://github.com/gdi2290/angular2-webpack2-starter.git"
  }
}
说明1:main选项是主入口模块的ID

   说明2:files选项是项目包含的两个目录。

   说明3:scripts选项是npm script(npm脚本)

             scripts也是对象,它的属性包含了很多,比如 "start": "npm run server:dev", 的意思是start命令对应的脚本是npm run server:dev。

    说明4:dependencies选项是项目依赖。

             比如@angular之类的依赖可以在node_modules找到对应的目录

            

    说明5:devDependencies是项目开发依赖,跟开发环境、调试打包有关咯。

    第二看src源代码目录了。

    

●app目录

  —about组件

  —home组件

 app.html文件

●main.browser.ts文件负责使用根模块(NgModule)去启动应用。

●index.html是src目录下默认打开的文件。里面做了app组件的使用和一些文件的引入。可以测试一下,先把原文内容注释掉,等测试完毕之后再放开。

  index.html我的内容:

<!DOCTYPE html>
<html 🆖>
<head>
  <title>Angular 2 Webpack 2 starter by @AngularClass</title>
  <base href="/">

</head>
<body>
    <div style="color:red;">冰雪奇缘</div>
</body>
</html>

打开localhost:3000,那么显示如下

OK!记得再退回到之间的内容里哦。

●dll.ts文件

// Polyfills就像验光师为近视患者配的眼镜,它可以让浏览器支持还不能支持的功能
export function polyfills(env?: any) {
  return [
    // 'ie-shim',

    'core-js/es6/symbol',
    'core-js/es6/object',
    'core-js/es6/function',
    'core-js/es6/parse-int',
    'core-js/es6/parse-float',
    'core-js/es6/number',
    'core-js/es6/math',
    'core-js/es6/string',
    'core-js/es6/date',
    'core-js/es6/array',
    'core-js/es6/regexp',
    'core-js/es6/map',
    'core-js/es6/set',
    'core-js/es6/weak-map',
    'core-js/es6/weak-set',
    'core-js/es6/typed',
    'core-js/es6/reflect',
    // 'core-js/es6/promise', // problem with firefox
    'core-js/es7/reflect',

    // zone.js
    'zone.js/dist/zone',
    'zone.js/dist/long-stack-trace-zone',

    // typescript helpers
    'ts-helpers',
  ];
}

// Angular 2 and other Vendor imports
//本意是供应商,提供angular2或者其他导入
export function vendors(env?: any) {
  return [
    '@angular/platform-browser',
    '@angular/platform-browser-dynamic',
    '@angular/compiler',
    '@angular/router',
    '@angular/forms',
    '@angular/common',
    '@angular/core',
    '@angular/http',

    '@angularclass/form-validators',
    '@angularclass/hmr',
  ];
}

// RxJS是javascript的扩展
export function rxjs(env?: any) {
  return [
    'rxjs/Observable',
    'rxjs/Subscription',
    'rxjs/Subject',
    'rxjs/BehaviorSubject',
    'rxjs/add/operator/map',
    'rxjs/add/operator/mergeMap',
    'rxjs/add/operator/distinctUntilChanged',
  ];
}

打开localhost:3000,查看源代码可以看到像下面的脚本引入,就是他们咯

●custom-typings.d.ts

 使用typings启动只能提示,这里是可以定制的。

step3:创建一个contact组件

以此熟悉一下源代码的单页逻辑结构。app目录下新建contact目录:

 

我直接把+about目录删掉,接下来填充如下代码。

app/app.html:

<div>
  <h1>Hello Angular 2 and Webpack 2</h1>
  <a href="#" routerLink="">Home</a>
  <a href="#" routerLink="contact">Contact</a>
  <!--contact路由的跳转链接,也就是路由使用咯-->
</div>

<main>
  <router-outlet></router-outlet>
  <!--这里是组件内容投掷的地方-->
</main>

<!--
<footer>
  <pre>appStore = {{ appStore.getState() | json }}</pre>
  AngularClass
</footer>
我不喜欢这块代码,直接删掉咯。
-->

app/index.ts:

mport { RouterModule } from '@angular/router';
import { NgModule } from '@angular/core';

import HomeModule from './home';

export const ROUTER_CONFIG = [
  { path: '', loadChildren: () => HomeModule },
  { path: 'contact', loadChildren: () => System.import('./contact')},
//组件代码外的路由配置
];

@NgModule({
  providers: [
  ],
  declarations: [
    // Components / Directives/ Pipes
  ],
  imports: [
    RouterModule.forChild(ROUTER_CONFIG),
  ],
})
export default class AppModule {
  static routes = ROUTER_CONFIG;
}

组件app/contact/index.ts:

import { CommonModule } from '@angular/common'
import { RouterModule } from '@angular/router';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ANGULARCLASS_FORM_VALIDATOR_DIRECTIVES } from '@angularclass/form-validators';

import { Contact } from './contact';
//引入contact.ts的模块

export const ROUTER_CONFIG = [
    { path: '', component: Contact, pathMatch: 'full' }
];

@NgModule({
    declarations: [
        // Components / Directives/ Pipes
        Contact,
        //模块定义Contact
        ...ANGULARCLASS_FORM_VALIDATOR_DIRECTIVES
    ],
    imports: [
        RouterModule.forChild(ROUTER_CONFIG),
        FormsModule,
        CommonModule
    ]
})
export default class ContactModule {
    static routes = ROUTER_CONFIG;
}
index.ts完整代码

组件app/contact/contact.ts:

import { Component } from '@angular/core';
@Component({
    templateUrl:"./contact.html"
})
export class Contact {
    localState = {
        email: ''
    };
    constructor() {
    }

}

app/contact/contact.html:

<div>我是contact页面</div>

最终可以看到contact路由的显示结果

二: 探索angular2的路由

这里的构建系统使用另一个脚手架。

1.搭建脚手架

git clone https://github.com/mgechev/switching-to-angular2.git router-steps

npm install

npm start

非常顺利,它直接打开浏览器可以看到结果

把多余的代码删掉,只剩下目录。如图。

打开,http://localhost:5555/dist/dev/ch6/ts/step-2/可以看到浏览器的结果

接下来关注step-1的内容,其目录为

2.启动应用的根组件app.ts

除了定义组件的Component、启动应用的bootstrap函数、本组件的其他内容,还引入了路由和路径策略。

import {APP_BASE_HREF, LocationStrategy, HashLocationStrategy} from '@angular/common';
//LocationStrategy是一个抽象类,定义了基于哈希HashLocationStrategy的路由和基于
//HTML5的路由
//HashLocationStrategy不支持服务端渲染
import {Route, Redirect, ROUTER_DIRECTIVES, ROUTER_PROVIDERS, RouteConfig} from '@angular/router-deprecated';
//ROUTER_PROVIDERS包含了路由的一组PROVIDER
//RouteConfig是一个装饰器
//Route用来定义单独的路由
//用来定义转发规则,从而定义路由的层级结构,所以ng2支持嵌套路由

之后的app.ts使用component装饰器定义组件,并使用bootstrap启动应用。

bootstrap(App, [
  ROUTER_PROVIDERS,
  { provide: LocationStrategy, useClass: HashLocationStrategy }
]);
//第二个参数是provider列表,共整个APP访问
//名称为LocationStrategy的provider,设置为Hash策略,默认值是基于HTML5的策略

基于HTML5的PathLocationStrategy必须提供APP_BASE_HREF。

3.使用@RouteConfig配置路由

@RouteConfig([
  new Route({ component: Home, name: 'Home', path: '/' }),
  new Route({ component: AddDeveloper, name: 'AddDeveloper', path: '/dev-add' }),
//  new Route({ component: DeveloperDetails, name: 'DeveloperDetails', path: '/dev-details/:id/...' }),
 new Redirect({ path: '/add-dev', redirectTo: ['/dev-add'] })
//当用户打开/add-dev时,会被转发到dev-add
]) class App {}

@RouteConfig装饰器接收路由数组作为参数。有两种类型的路由,Route和Redirect。

Route必须定义3个属性。

component,路由关联的是哪个组件

name,路由名称,模板使用它。

path ,路径,浏览器地址栏使用它。

 转发器只有两个属性

●path需要被转发的路径。

●redirectTo目标路径  

4.routerLink和router-outlet的用法

ch6/ts/step-1/app.ts模板代码:

<nav class="navbar navbar-default">
      <ul class="nav navbar-nav">
        <li><a [routerLink]="['/Home']">Home</a></li>
        <li><a [routerLink]="['/AddDeveloper']">Add developer</a></li>
      </ul>
    </nav>
    <router-outlet></router-outlet>

●routerLink用来给指定路由添加链接。接收数组,包含名称和值。

●routeroutlet用来定义路由的渲染容器。

那么打开http://localhost:5555/dist/dev/ch6/ts/step-1/#/dev-add,可看到浏览器结果。可跳转的哦。

 

总体上分为3个部分,boostrap启动的provider列表、路由配置和路由的使用。

三: AsyncRoute懒加载

好棒呢,轻松实现懒加载。

只有一步: 引入AsyncRoute类

替换掉@RouteConfig里面的Route就行了。

@RouteConfig([
  new AsyncRoute({
    loader: () =>
      System.import('./home')
        .then(m => m.Home),
      name: 'Home',
      path: '/'
    }),
  new AsyncRoute({
    loader: () =>
      System.import('./add_developer')
        .then(m => m.AddDeveloper),
      name: 'AddDeveloper',
      path: '/dev-add'
    }),
//  new Route({ component: DeveloperDetails, name: 'DeveloperDetails', path: '/dev-details/:id/...' }),
  new Redirect({ path: '/add-dev', redirectTo: ['/dev-add'] })
])

完整的代码是

import {Component} from '@angular/core';
import {bootstrap} from '@angular/platform-browser-dynamic';
import {APP_BASE_HREF, LocationStrategy, HashLocationStrategy} from '@angular/common';
import {AsyncRoute, Redirect, ROUTER_DIRECTIVES, ROUTER_PROVIDERS, RouteConfig} from '@angular/router-deprecated';
import {DeveloperCollection} from './developer_collection';
import {Developer} from './developer';

@Component({
  selector: 'app',
  template: `
    <nav class="navbar navbar-default">
      <ul class="nav navbar-nav">
        <li><a [routerLink]="['/Home']">Home</a></li>
        <li><a [routerLink]="['/AddDeveloper']">Add developer</a></li>
      </ul>
    </nav>
    <router-outlet></router-outlet>
  `,
  providers: [DeveloperCollection],
  directives: [ROUTER_DIRECTIVES]
})
@RouteConfig([
  new AsyncRoute({
    loader: () =>
      System.import('./home')
        .then(m => m.Home),
      name: 'Home',
      path: '/'
    }),
  new AsyncRoute({
    loader: () =>
      System.import('./add_developer')
        .then(m => m.AddDeveloper),
      name: 'AddDeveloper',
      path: '/dev-add'
    }),
//  new Route({ component: DeveloperDetails, name: 'DeveloperDetails', path: '/dev-details/:id/...' }),
  new Redirect({ path: '/add-dev', redirectTo: ['/dev-add'] })
])
class App {}

bootstrap(App, [
  ROUTER_PROVIDERS,
  { provide: LocationStrategy, useClass: HashLocationStrategy }
]);
懒加载的app.ts

AsyncRoute类构造函数接受一个对象作为参数

●loader:一个函数,返回一个需要兑现的promise。

●name:路由的名字

●path路由所对应的请求路径。

注意:这里使用的System类,只是其中一种方式而已,使用require.js也能实现相同的功能。

到底是不是懒加载,我们可以查看一下。

打开http://localhost:5555/dist/dev/ch6/ts/step-1-async网址,375个请求,并没有把所有路由组件都加载了

点击另外一个路由,这时375个请求变成了376个请求,也就是第二个路由。

 

 

posted @ 2017-07-02 17:35  陈蒙的技术空间  阅读(467)  评论(0编辑  收藏  举报