[Angular2速成班]來寫個TodoApp(1)-基本原理與架構

之前的文章介紹過Angular CLI的基本用法之後,本篇文章開始就來寫一個簡單的TodoApp,藉此來練習Angular2的各種特色。

基本觀念

首先,我們必須先知道,Angular2引入了Web Component的概念,也就是一個Angular2 app基本上是由數個元件(component)來組成的,因此在設計時我們可以適當的將預期的畫面拆解成數個component,然後各司其職,並且適當的彼此溝通,來完成我們預期的程式。

那麼要如何建立一個component呢?其實在之前Hello World的文章我們使用Angular CLI建立一個專案時,就已經有一個最基本app-root的component囉!

我們可以打開src/app/app.component.ts,看到以下程式

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app works!';
}

在這裡我們可以看到@Component就是用來將AppComponent這個class"裝飾"成一個component,這是在ES6提出來的一種decorator語法,使用@#XXXX來從不同的切面對程式進行描述,雖然大部分的瀏覽器都還不支援,但我們使用TypeScript撰寫時,編譯器就能將程式轉換成大部分瀏覽器都看得懂得程式碼了!

Angular2製作了許多的decorator,而@component就是其中一個,因此只要在class上面使用@component宣告,Angular2核心就能夠知道這是一個component囉!而裡面目前看到的三個屬性:

selector: 用來表示在HTML上的哪個element要套用這個component

templateUrl: 用來表示這個component的view存放位置

styleUrls: 用來加入專屬於這個component的css檔案位置

如果要用JavaScript來寫的話看起來大概是這樣(程式碼取自官方文件):

(function(app) {
  app.AppComponent =
    ng.core.Component({
      selector: 'my-app',
      template: '<h1>My First Angular App</h1>'
    })
    .Class({
      constructor: function() {}
    });
})(window.app || (window.app = {}));

個人感覺是滿不習慣的啦XD

那麼這個AppComponent是在那裡顯示的呢?我們可以再來看看src/index.html

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>Angular2DotblogsDemo</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>

裡面的<app-root>Loading...</app-root>這段就是呈現AppComponent的部分!在瀏覽器剛打開時,因為還看不懂app-root是什麼,所以會直接呈現裡面的Loading...,當JavaScript程式碼讀取完後游Angular2接手時就會把適當的內容產生上去囉。

值得稍微注意一下的是,這段HTML裡面我們看不到<script src"..." />這樣的內容,但在使用ng build打包程式時,會透過webpack自動幫我們把打包好的程式加入這段HTML裡面。

最後我們來看看src/app/app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

我們在一次看到了一個decorator,不過這次是@NgModule,Angular2除了component觀念外,也可以透過module對複雜的components做分類管理,之後有機會再來詳細介紹,現在只需要知道AppModule是我們程式最主要的module,且是使用@NgModule裝飾就可以了,在declarations裡面放了一開始就有的AppComponent,imports裡面預設加入了三個最常用的module,以及bootstrap裡面宣告我們會由AppComponent來啟動,providers裡面目前是空的,以後我們會加入需要的provider。

TodoApp架構

有了基本的component概念後,我們接著來看看一個TodoApp需要那些元件,初步我們規劃成3個component,如下圖

加入第一個Component

接下來我們就來實際建立一個component來看看吧!我們先建立一個標題區的component,可以使用ng g c header指令來建立,執行完後會發現我們的專案src/app下面多了一個header目錄,裡面有4個檔案

其中header.component.spec.ts是用來寫unit test的,在介紹觀念的初期我們不會使用,因此可以考慮把它刪掉,或保留以後再把測試程式加進去。

仔細看看檔案和目錄的名稱,我們可以發現使用Angular CLI建立的檔案名稱都非常明確,也嚴格遵循官方推薦的Style Guide準則,這讓我們在開發時能夠更加順暢的辨識各種檔案的功能。

另外在src/app/app.module.ts中我們可以看到declarations裡面也加入了HeaderComponent。

我們可以先來看看header.component.ts的內容:

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

@Component({
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

}

有沒有覺得跟之前的AppComponent非常類似啊!透過Angular CLI,要產生一個component就是一行指令的動作而已,很方便吧!

接下來我們把header.component.html的內容改成如下:

<h1>歡迎來到Todo App</h1>

然後把app.component.html的內容從原本的

<h1>
  {{title}}
</h1>

改成

<app-header></app-header>

然後回到命令提示字元輸入ng serve啟動模擬的伺服器,再打開瀏覽器輸入http://127.0.0.1:4200,就可以看到我們設計的HeaderComponent正常顯示出來啦!

加入其他Components

有了建立第一個component的概念之後,接下來就簡單多啦!我們可以使用 ng g c add-formng g c todo-items來分別建立AddFormComponent和TodoItemsComponent!

接著我們先把模擬的畫面程式碼填入,首先是src/app/add-form/add-form.component.html

<input type="text" placeholder="請輸入代辦事項"> <button>增加</button>

接著是src/app/todo-items/todo-items.component.html

<ul>
  <li><label for="chk_1"><input id="chk_1" type="checkbox">Todo Item 1</label> | <a href="#">刪除</a></li>
  <li><label for="chk_2"><input id="chk_2" type="checkbox">Todo Item 2</label> | <a href="#">刪除</a></li>
  <li><label for="chk_3"><input id="chk_3" type="checkbox">Todo Item 3</label> | <a href="#">刪除</a></li>
</ul>

最後再把src/app/app.component.html修改為:

<app-header></app-header>

<app-add-form></app-add-form>

<app-todo-items></app-todo-items>

再回到瀏覽器,就可以看到我們的TodoApp基本架構的畫面囉。

之後我們的目標就是把這些基本功能完成,同時學習Angular2啦!

單元回顧

本篇文章中我們學到了一些Angular2的基本原理,以及decorator的使用方式,接著透過Angular CLI建立了3個component,並且觀察到了Angular CLI產生檔案時的變化,透過Angular CLI我們可以快速產生component,減少很多寫程式的時間,讓我們能更專注在核心程式碼中;同時我們也注意到Angular CLI產生的檔案名稱結構都非常明確,這可以幫助我們更容易辨識每個檔案的功能;我們已經把基本的畫面架構完成了,在下一篇文章開始就會慢慢把程式碼填入囉。

本篇文章的程式碼放在https://github.com/wellwind/Angular2DotblogsDemo/tree/TodoAppScaffold,之後的文章都會以Angular2DotblogsDemo這個repository上建立新的branch,方便大家觀察每個階段的程式碼變化。