Angular 2.0 SPA应用 - 从脚手架开始 (1)

作者: 程序员长春 | 来源:发表于2017-03-08 22:24 被阅读1469次

    前言

    今天是2017年3月7日,Angular 2.0目前最新版本是 2.0.0-beta.17。网络上搜索到的Augular项目及实例,大部分都是1.x版本的,即使是使用2.x版本的Demo,由于写作时间关系,部分的代码显得有些过时。
    本系列希望通过一步步实现一个邮件发送应用,讲解Angular 2.0中的Route、Module、Component、Service、Dependency Inject等的实现。

    准备工作

    打开网站 https://plnkr.co/edit,点击“New”->"Angular 2.x",新建一个基本的Angular 2.0脚手架项目。
    脚手架项目包含6个文件,分别是 config.js、index.html、README.md、src/app.ts、src/main.ts、style.css。其中,style.css是一个空文件,可以忽略之;README.md文件,熟悉Github这个全球最大的gay gay land的同学应该知道,这是markdown语法的项目说明文件,目前也可以忽略之。

    Plunker编辑器
    1. index.html
    <!DOCTYPE html>
    <html>
      <head>
        <base href="." />
        <title>angular2 playground</title>
        <link rel="stylesheet" href="style.css" />
        <script src="https://unpkg.com/core-js@2.4.1/client/shim.min.js"></script>
        <script src="https://unpkg.com/zone.js/dist/zone.js"></script>
        <script src="https://unpkg.com/zone.js/dist/long-stack-trace-zone.js"></script>
        <script src="https://unpkg.com/reflect-metadata@0.1.3/Reflect.js"></script>
        <script src="https://unpkg.com/systemjs@0.19.31/dist/system.js"></script>
        <script src="config.js"></script>
        <script>
        System.import('app')
          .catch(console.error.bind(console));
      </script>
      </head>
      <body>
        <my-app>
        loading...
      </my-app>
      </body>
    </html>
    

    Index.html文件后面基本不会进行任何修改,有兴趣了解其中包含JS文件的含义及作用的,请自行Google,俺就不做大自然的搬运工了。
    按照惯例,先给index.html,<title></title>标签后添加Bootstrap 资源链接。

    <title>angular2 playground</title>
     ......
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="  crossorigin="anonymous"></script>
    <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
     ......
    

    index.html文件中有一段这样的代码

    <my-app>
        loading...
    </my-app>
    

    <my-app>标签是非HTML标准标签,这是一个Angular Component (组件),需要有一个文件实现对应的my-app组件。
    在index.html文件中还引用了config.js文件。

    1. config.js
    System.config({
      //use typescript for compilation
      transpiler: 'typescript',
      //typescript compiler options
      typescriptOptions: {
        emitDecoratorMetadata: true
      },
      paths: {
        'npm:': 'https://unpkg.com/'
      },
      //map tells the System loader where to look for things
      map: {
        
        'app': './src',
        
        '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
        '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
        '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
        '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
        '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
        '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
        '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
        '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
        
        '@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js',
        '@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js',
        '@angular/compiler/testing': 'npm:@angular/compiler/bundles/compiler-testing.umd.js',
        '@angular/platform-browser/testing': 'npm:@angular/platform-browser/bundles/platform-browser-testing.umd.js',
        '@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js',
        '@angular/http/testing': 'npm:@angular/http/bundles/http-testing.umd.js',
        '@angular/router/testing': 'npm:@angular/router/bundles/router-testing.umd.js',
        
        'rxjs': 'npm:rxjs',
        'typescript': 'npm:typescript@2.0.2/lib/typescript.js'
      },
      //packages defines our app package
      packages: {
        app: {
          main: './main.ts',
          defaultExtension: 'ts'
        },
        rxjs: {
          defaultExtension: 'js'
        }
      }
    });
    

    config.js文件,基本不需要修改,改名控的同学可以修改的位置就两个地方,分别是'/src'(源代码路径)和'./main.ts'(应用程序入口):

    'app': './src',
     ......
    main: './main.ts',
    
    1. main.ts 应用程序入口
    //main entry point
    import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
    import {AppModule} from './app';
    //从当前文件(main.ts)同文件夹内的app.ts(不需要写ts后缀)文件中导入AppModule类
    platformBrowserDynamic().bootstrapModule(AppModule)
    //启动AppModule
    
    1. app.ts
    //our root app component
    import {Component, NgModule} from '@angular/core'
    import {BrowserModule} from '@angular/platform-browser'
    //组件模板
    @Component({
      selector: 'my-app',
      template: `
        <div>
          <h2>Hello {{name}}</h2>
        </div>
      `,
    })
    //组件类
    export class App {
         name:string;
         constructor() {
           this.name = 'Angular2'
         }
    }
    // 启动模块 AppModule
    @NgModule({
      imports: [ BrowserModule ],
      declarations: [ App ],
      bootstrap: [ App ]
    })
    export class AppModule {}
    

    Template 中使用 ` 而不是单引号 ' ,原因请看 模板字符串 说明。
    因为代码不多,Module、Component、Template三个部分写在同一个ts文件中。

    我们的目标

    • 美观大方的界面
    • 实现SPA页面路由
    • 实现组件Javascript、HTML代码文件分离
    界面布局实现

    把app.ts拆分为app.ts、app.component.ts、app.template.html

    1. app.ts
     //our root app component
     import {NgModule} from '@angular/core'
     import {BrowserModule} from '@angular/platform-browser'
    
     import {App} from './app.component' 
    
     @NgModule({
          imports: [ BrowserModule ],
          declarations: [ App ],
          bootstrap: [ App ]
    })
    export class AppModule {}
    
    1. app.component.ts**
    import {Component} from '@angular/core'
    @Component({
      selector: 'my-app',
      moduleId: __moduleName,
      templateUrl: './app.template.html'
    })
    export class App {
      name:string;
      constructor() {
        this.name = 'Angular2'
      }
    }
    
    1. app.template.html
    <nav class="navbar navbar-inverse navbar-fixed-top">
      <div class="container-fluid">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#topNavbar">
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">AngularJS Demo</a>
        </div>
        <div class="collapse navbar-collapse" id="topNavbar">
          <ul class="nav navbar-nav">
            <li class="active"><a href="#">首页</a></li>
            <li><a href="#">Page 1</a></li>
          </ul>
          <ul class="nav navbar-nav navbar-right">
            <li><a href="#"><span class="glyphicon glyphicon-user"></span> Sign Up</a></li>
            <li><a href="#"><span class="glyphicon glyphicon-log-in"></span> Login</a></li>
          </ul>
        </div>
      </div>
    </nav>
    <nav class="navbar navbar-default navbar-fixed-bottom">
      <div class="container-fluid">
         <div class="row">
                <div class="col-md-12 navbar-text">© 2017 | <a href="http://www.jianshu.com/u/15de06e8d059" target="_blank" class="navbar-link">程序员长春</a>
                </div>
            </div>
      </div>
    </nav>
    
    组件代码分离

    为简单起见,只实现两个路由页面,home和login。

    1. 添加文件 src/home/home.component.ts、src/home/home.template.html
      ** home.component.ts **
     import {Component} from '@angular/core'
    
     @Component({
      selector: 'home',
      moduleId: __moduleName,
      templateUrl: './home.template.html'
    })
    export class HomeComponent {
    }
    

    ** home.template.html **

    // 这部分HTML只是为了页面好看,随便写了点,如果没有,也是可以的。
    <div class="jumbotron">
      <div class="container">
        <div class="page-header text-center">
          <h1>AngularJS Demo</h1>
        </div>
        <p>AngularJS 演示程序,包括且不限于Module, Route, LocalStorageService, ajax web API consumer等功能。</p>
      </div>
    </div>
    
    1. 添加文件 src/login/login.component.ts、src/login/login.template.html
      ** login.component.ts **
     import {Component} from '@angular/core'
    
     @Component({
      selector: 'login',
      moduleId: __moduleName,
      templateUrl: './login.template.html'
    })
    export class LoginComponent{
    }
    

    ** login.template.html **

    // 这部分HTML只是为了页面好看,随便写了点,如果没有,也是可以的。
    <div class="container">
      <div id="loginbox" style="margin-top:100px;" class="mainbox col-md-6 col-md-offset-3 col-sm-8 col-sm-offset-2">
        <div class="panel panel-info">
          <div class="panel-heading">
            <div class="panel-title">Sign In</div>
          </div>
          <div style="padding-top:30px" class="panel-body">
            <div style="display:none" id="login-alert" class="alert alert-danger col-sm-12"></div>
            <form id="loginform" class="form-horizontal" role="form">
              <div style="margin-bottom: 25px" class="input-group">
                <span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span>
                <input id="login-username" type="text" class="form-control" name="username" value="" placeholder="username or email">
              </div>
              <div style="margin-bottom: 25px" class="input-group">
                <span class="input-group-addon"><i class="glyphicon glyphicon-lock"></i></span>
                <input id="login-password" type="password" class="form-control" name="password" placeholder="password">
              </div>
              <div style="margin-top:10px" class="form-group">
                <!-- Button -->
                <div class="col-sm-12 controls">
                  <a id="btn-login" href="#" class="btn btn-success">Login  </a>
                </div>
              </div>
            </form>
          </div>
        </div>
      </div>
    </div>
    
    页面路由实现
    1. 修改app.ts, app.template.html
      ** app.ts **
     //our root app component
     import {NgModule} from '@angular/core'
     import {BrowserModule} from '@angular/platform-browser'
    import {App} from './app.component'
    --- 添加路由代码 ---
    import { RouterModule, Routes } from '@angular/router';
    import { HomeComponent }   from './home/home.component';
    import { LoginComponent }     from './login/login.component';
    const appRoutes: Routes = [
      { path: 'home', component: HomeComponent },
      { path: 'login', component: LoginComponent },
      { path: '',   redirectTo: 'home', pathMatch: 'full' }
    ];
    @NgModule({
      imports: [ BrowserModule, RouterModule.forRoot(appRoutes) ],
      declarations: [ App, HomeComponent, LoginComponent ],
      bootstrap: [ App ]
    })
    --- 修改结束 ---
    export class AppModule {}
    

    ** app.template.html **
    修改超级链接为路由链接,加入路由选择器"<router-outlet></router-outlet>"。

    --- 新代码 ---
    <a class="navbar-brand" routerLink="/home">{{ name }} Demo</a>
    ... ... 
    <li><a routerLink="/login"><span class="glyphicon glyphicon-log-in"></span> Login</a></li>
    ......
    <router-outlet></router-outlet>
    

    总结

    在本文中,我们从一个最基本的Angular脚手架,一步步添加内容,实现了Bootstrap布局,Angular 路由,一个简单的首页和一个登陆页面。

    首页
    登陆
    在线预览请点击: Angular 2.0 Demo

    下篇预告

    添加一个受保护页面,只有通过验证后才能访问收保护页面。

    系列文章目录

    1. Angular 2.0 SPA应用 - 从脚手架开始 (1)
    2. Angular 2.0 SPA应用 - 身份认证(2)

    相关文章

      网友评论

      • ebd030a9c1f8:写的很好啊,十分适合,入门的我,感谢感谢

      本文标题:Angular 2.0 SPA应用 - 从脚手架开始 (1)

      本文链接:https://www.haomeiwen.com/subject/vjhvgttx.html