Angular2 是 Google 用於構建基於瀏覽器的複雜應用的下一代 MV* 框架。該項目是我學習 Angular2 的入門項目,我以爲它很友好地表達了 Angular2 的有趣實現方式,並更易於瞭解和入門。它涵蓋了 Angular2 的一些基本概念,包括:組件(Component)、模型(Model)、服務(Service)、管道(Pipe)、傳入傳出(Input / Output)以及事件播散(EventEmitter)等使用方法,並介紹了項目的基本組織結構等。html
Anguar2 可以使用 ES6 或 TypeScript 來編寫,我在這裏使用了 TypeScript。node
若您對本文感興趣,也很是歡迎來個人 GitHub 主頁閱讀,同時也是本文的項目代碼地址(https://github.com/DotHide/angular2-quickstart)git
如下羅列的是該項目中的幾個重要概念:github
在 Angular2 中,Component 是咱們在頁面中構建自定義元素和業務邏輯的主要方式。在 Angular1 中,咱們則是經過 directives,controllers 以及 scope 來實現,而如今全部的這一切都結合到了 Component 中。Component 中須要定義 selector 和 templete,即組件生效的標記和對應的 HTML 模板typescript
// Component 是 Angular2 提供的組件,使用前須要先 import import {Component} from "angular2/core"; @Component({ selector: 'todo-input', template: ` <div> <form (submit)="onSubmit()"> <input type="text" [(ngModel)]="todoItem.title"> </form> </div> ` })
其中 templete 使用到了多行模板的用法,即便用\
`做爲模板開始結束標記npm
定義組件後須要定義相匹配的類:json
export class TodoInput { }
類名使用 UpperCamelCase,如:TodoInput,文件名及 selector 使用 DashCase,如:todo-input(.ts)bootstrap
任何 Component 在使用前須要 import,若是是組件中的組件須要在 @Component 中定義 directives,如:瀏覽器
@Component({ selector: 'todo-app', directives: [TodoInput], templete: '...' })
模型比較簡單,通知只須要定義好構造函數及相關方法便可:bash
export class TodoModel{ constructor( public title:string = "", public status:string = "started" ){} toggle():void{ this.status = this.status == 'completed'? 'started': 'completed'; } }
這裏構造函數的參數定義了 public,這樣能夠被其餘類訪問到
服務一般須要聲明 @Injectable()
,通常服務也會 import 模型類
import {Injectable} from "angular2/core"; import {TodoModel} from "../models/todo-model"; @Injectable() export class TodoService { todos:TodoModel[] = [ new TodoModel("arm"), new TodoModel("battle"), new TodoModel("code", "completed"), new TodoModel("eat"), new TodoModel("fly"), new TodoModel("sleep", "completed") ]; addTodoItem(item:TodoModel) { ... } toggleTodo(todo: TodoModel) { ... } }
聲明瞭 Injectable
以後,須要在入口函數中 inject 相關服務
bootstrap(TodoApp, [TodoService]);
即 Angular 1 中的 ng-repeat
,這裏用法有些差別,如:
<ul> <li *ngFor="#todo of todoService.todos"> {{ todo }} </li> </ul>
使用 ngFor 時須要在前加 號( 號表示該動做將引發模板的變化),循環中的個體元素引用前須要添加 # 號,這些都是語法上的變化。
ngModel
用於雙向綁定,使用 [(ngModel)]=
來定義,[()]
專門用於定義雙向綁定。
@Component({ selector: 'todo-input', template: ` <div> <form (submit)="onSubmit()"> <input type="text" [(ngModel)]="todoItem.title"> </form> </div> ` }) export class TodoInput { todoItem:TodoModel = new TodoModel(); constructor() {} }
使用 ngModel 前須要在 class 中定義變量,變量能夠是任何類型。
利用 Pipe 來篩選(filter)數據,與 Angualr1 十分相似,這裏仍是使用 |
符號來定義篩選,如:
// todo-list.ts ... @Component({ selector: 'todo-list', pipes: [SearchPipe], directives: [TodoItemRender], template: `<div> <ul> <li *ngFor="#todo of todoService.todos | search "> <todo-item-render [todo]="todo" (toggle)="todoService.toggleTodo($event)"> </todo-item-render> </li> </ul> </div>` }) // search-pipe.ts ... @Pipe({ name: 'search' }) export class SearchPipe { transform(items) { // 定義轉換邏輯,用於結果輸出,這裏是篩選出以 s 字符開頭的項目 return value.filter((item) => { return item.title.startsWith('s'); }); } }
使用 Pipe 時須要先在 Component 中定義 pipes 屬性,而後在 html 中使用 Pipe 的 name。
固然,這裏的 Pipe 還能夠傳遞參數,仍然以上面的爲例,能夠傳參設定 search 的內容,如:
// search-pipe.ts ... @Pipe({ name: 'search' }) export class SearchPipe { // 增長 term 參數 transform(items, [term]) { // 定義轉換邏輯,用於結果輸出,這裏是篩選出以 s 字符開頭的項目 return value.filter((item) => { return item.title.startsWith(term); }); } }
這裏分兩步修改,首先修改 SearchPipe 類中的方法,增長 term 參數,而後再修改使用處的代碼
// todo-list.ts ... @Component({ selector: 'todo-list', pipes: [SearchPipe], directives: [TodoItemRender], template: `<div> <ul> <li *ngFor="#todo of todoService.todos | search = 's' "> <todo-item-render [todo]="todo" (toggle)="todoService.toggleTodo($event)"> </todo-item-render> </li> </ul> </div>` })
這裏咱們先看到 search 進行了賦值,咱們進一步把這個賦值變爲一個輸入項(@Input),這也是 Angular2 中特殊用法:
// todo-list.ts import {Component, Input} from "angular2/core"; ... @Component({ selector: 'todo-list', pipes: [SearchPipe], directives: [TodoItemRender], template: `<div> <ul> <li *ngFor="#todo of todoService.todos | search = term "> <todo-item-render [todo]="todo" (toggle)="todoService.toggleTodo($event)"> </todo-item-render> </li> </ul> </div>` }) export class TodoList { @Input() term; // 定義該項是從外部輸入的 constructor(public todoService: TodoService) { } }
由此,須要在使用 TodoList 組件的地方(即外部),定義相關的屬性。
<search-box (update)="term = $event"></search-box> ... <todo-list [term]="term"></todo-list>
這裏表示從搜索框輸入過來的值(前一個 term),被賦值到了 todo-list 的 [term]
屬性中,並傳遞到 TodoList 類的輸入項中去
事件散播,又一個 Angular2 的新特性,用於將組件內部的事件向上散播,如:
@Component({ selector: 'todo-item-render', template: ` <style> .completed { text-decoration: line-through; } </style> <span [ngClass]="todo.status">{{ todo.title }}</span> <button (click)="toggle.emit(todo)">Toggle</button> ` }) export class TodoItemRender { @Input() todo; @Output() toggle = new EventEmitter(); }
這裏的 toggle 是 EventEmitter 對象,被聲明爲 Output 後,能夠將按鈕的 click 事件向上散播成爲 todo-list 中該組件的 toggle 事件,其中的 $event
就是 TodoItemRender 類中聲明的 todo(此 todo 又是來自外部輸入),然後再觸發 toggle 事件對應的業務邏輯。
請按如下步驟打開項目:
# 安裝 TypeScript $ npm install -g tsd typescript # 安裝項目依賴 $ npm install # 啓動項目 $ npm start
琢磨調用第三方庫花了些時間,這裏也記錄一下。以添加 lodash 庫爲例,須要通過以下5個步驟:
$ npm install lodash --save
安裝後到
package.json
文件中查看,若有 loash 再進入下一步
$ tsd install lodash
若是沒有 tsd 命令行工具,則先安裝
$ npm install -g tsd
在 index.html
文件中引用:
<script src="node_modules/lodash/lodash.js"></script>
在 System.config()
中添加 path
:
System.config({ paths: { lodash: './node_modules/lodash/lodash.js' } });
在須要使用的地方 import
:
import * as _ from "lodash"; ... function (){ _.sum([4, 2, 8, 6]); // → 20 }