Angular 2.0 SPA應(yīng)用 - 從腳手架開(kāi)始 (1)

前言

今天是2017年3月7日,Angular 2.0目前最新版本是 2.0.0-beta.17。網(wǎng)絡(luò)上搜索到的Augular項(xiàng)目及實(shí)例,大部分都是1.x版本的,即使是使用2.x版本的Demo,由于寫(xiě)作時(shí)間關(guān)系,部分的代碼顯得有些過(guò)時(shí)。
本系列希望通過(guò)一步步實(shí)現(xiàn)一個(gè)郵件發(fā)送應(yīng)用,講解Angular 2.0中的Route、Module、Component、Service、Dependency Inject等的實(shí)現(xiàn)。

準(zhǔn)備工作

打開(kāi)網(wǎng)站 https://plnkr.co/edit,點(diǎn)擊“New”->"Angular 2.x",新建一個(gè)基本的Angular 2.0腳手架項(xiàng)目。
腳手架項(xiàng)目包含6個(gè)文件,分別是 config.js、index.html、README.md、src/app.ts、src/main.ts、style.css。其中,style.css是一個(gè)空文件,可以忽略之;README.md文件,熟悉Github這個(gè)全球最大的gay gay land的同學(xué)應(yīng)該知道,這是markdown語(yǔ)法的項(xiàng)目說(shuō)明文件,目前也可以忽略之。

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文件后面基本不會(huì)進(jìn)行任何修改,有興趣了解其中包含JS文件的含義及作用的,請(qǐng)自行Google,俺就不做大自然的搬運(yùn)工了。
按照慣例,先給index.html,<title></title>標(biāo)簽后添加Bootstrap 資源鏈接。

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

index.html文件中有一段這樣的代碼

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

<my-app>標(biāo)簽是非HTML標(biāo)準(zhǔn)標(biāo)簽,這是一個(gè)Angular Component (組件),需要有一個(gè)文件實(shí)現(xiàn)對(duì)應(yīng)的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文件,基本不需要修改,改名控的同學(xué)可以修改的位置就兩個(gè)地方,分別是'/src'(源代碼路徑)和'./main.ts'(應(yīng)用程序入口):

'app': './src',
 ......
main: './main.ts',
  1. main.ts 應(yīng)用程序入口
//main entry point
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {AppModule} from './app';
//從當(dāng)前文件(main.ts)同文件夾內(nèi)的app.ts(不需要寫(xiě)ts后綴)文件中導(dǎo)入AppModule類
platformBrowserDynamic().bootstrapModule(AppModule)
//啟動(dòng)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'
     }
}
// 啟動(dòng)模塊 AppModule
@NgModule({
  imports: [ BrowserModule ],
  declarations: [ App ],
  bootstrap: [ App ]
})
export class AppModule {}

Template 中使用 ` 而不是單引號(hào) ' ,原因請(qǐng)看 模板字符串 說(shuō)明。
因?yàn)榇a不多,Module、Component、Template三個(gè)部分寫(xiě)在同一個(gè)ts文件中。

我們的目標(biāo)

  • 美觀大方的界面
  • 實(shí)現(xiàn)SPA頁(yè)面路由
  • 實(shí)現(xiàn)組件Javascript、HTML代碼文件分離
界面布局實(shí)現(xiàn)

把a(bǔ)pp.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="#">首頁(yè)</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.itdecent.cn/u/15de06e8d059" target="_blank" class="navbar-link">程序員長(zhǎng)春</a>
            </div>
        </div>
  </div>
</nav>
組件代碼分離

為簡(jiǎn)單起見(jiàn),只實(shí)現(xiàn)兩個(gè)路由頁(yè)面,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只是為了頁(yè)面好看,隨便寫(xiě)了點(diǎn),如果沒(méi)有,也是可以的。
<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只是為了頁(yè)面好看,隨便寫(xiě)了點(diǎn),如果沒(méi)有,也是可以的。
<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>
頁(yè)面路由實(shí)現(xiàn)
  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 ]
})
--- 修改結(jié)束 ---
export class AppModule {}

** app.template.html **
修改超級(jí)鏈接為路由鏈接,加入路由選擇器"<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>

總結(jié)

在本文中,我們從一個(gè)最基本的Angular腳手架,一步步添加內(nèi)容,實(shí)現(xiàn)了Bootstrap布局,Angular 路由,一個(gè)簡(jiǎn)單的首頁(yè)和一個(gè)登陸頁(yè)面。

首頁(yè)

登陸

在線預(yù)覽請(qǐng)點(diǎn)擊: Angular 2.0 Demo

下篇預(yù)告

添加一個(gè)受保護(hù)頁(yè)面,只有通過(guò)驗(yàn)證后才能訪問(wèn)收保護(hù)頁(yè)面。

系列文章目錄

  1. Angular 2.0 SPA應(yīng)用 - 從腳手架開(kāi)始 (1)
  2. Angular 2.0 SPA應(yīng)用 - 身份認(rèn)證(2)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容