基于Angular 2 CLI開發(fā)CRUD應(yīng)用程序
譯文【譯者注】本文應(yīng)用開發(fā)及測(cè)試環(huán)境為Mac平臺(tái)(即類Linux環(huán)境);因此,使用Windows平臺(tái)的讀者在使用CLI時(shí)可能需要作一定的調(diào)整。所謂CLI,實(shí)際上是Angular 2新引入的一種命令行操作方式,在這種方式下能夠?qū)ΤR?guī)的Angular 2操作以更快的方式實(shí)現(xiàn)。另外,本文作者使用的Javascript腳本是TypeScript。還有,作者使用了Karma工具(https://karma-runner.github.io/)對(duì)文中的TypeScript腳本進(jìn)行了較全面的單元測(cè)試。因此,雖然本文介紹的是一個(gè)基礎(chǔ)型Angular 2實(shí)例開發(fā)過(guò)程,但是還是值得一讀。
簡(jiǎn)介
Angular 2是一個(gè)世界著名的開源Web前端開發(fā)框架,用于構(gòu)建跨移動(dòng)設(shè)備和桌面平臺(tái)的Web應(yīng)用程序。在本文中,我們將開發(fā)一個(gè)基于Angular 2 CLI方式的Todo Web應(yīng)用程序。這個(gè)程序中實(shí)現(xiàn)的基本功能包括允許用戶:
使用輸入字段快速創(chuàng)建新的todo任務(wù)
切換todo任務(wù)的完成與未完成狀態(tài)
刪除不再需要的todo任務(wù),等等
【注意】本文示例工程源碼下載地址是https://github.com/sitepoint-editors/angular2-todo-app。上述工程的一個(gè)在線展示網(wǎng)址是https://sitepoint-editors.github.io/angular2-todo-app/。下面僅給出這個(gè)程序的一個(gè)靜態(tài)截圖。
Angular CLI簡(jiǎn)介
創(chuàng)建一個(gè)新的Angular 2應(yīng)用程序最簡(jiǎn)單的方法之一是使用全新的Angular命令行界面(CLI)。CLI允許您實(shí)現(xiàn): 生成新的Angular 2應(yīng)用程序的樣板文件代碼
向現(xiàn)有的Angular 2應(yīng)用程序添加指定的功能(包括組件、指令、服務(wù)、管道等)
若要安裝Angular的CLI,請(qǐng)運(yùn)行如下命令:
$ npm install -g angular-cli
這將在您的系統(tǒng)中以全局方式安裝ng命令。
為了驗(yàn)證您的安裝是否成功,您可以運(yùn)行如下命令:
$ ng version
這個(gè)命令應(yīng)會(huì)顯示你已經(jīng)安裝的angular-cli版本號(hào)。更多的細(xì)節(jié),請(qǐng)參考官方安裝說(shuō)明(https://github.com/angular/angular-cli#installation)。
生成Todo應(yīng)用程序
現(xiàn)在,我們已經(jīng)安裝了Angular CLI。下面,我們可以使用它來(lái)生成我們的Todo應(yīng)用程序了,命令如下:
- $ ng new angular2-todo-app
這將創(chuàng)建一個(gè)目錄結(jié)構(gòu),其中包含我們所需要的一切基礎(chǔ)內(nèi)容,如下圖所示:
├── angular-cli-build.js
├── angular-cli.json
├── config
│ ├── environment.dev.ts
│ ├── environment.js
│ ├── environment.prod.ts
│ ├── karma.conf.js
│ ├── karma-test-shim.js
│ └── protractor.conf.js
├── e2e
│ ├── app.e2e-spec.ts
│ ├── app.po.ts
│ ├── tsconfig.json
│ └── typings.d.ts
├── package.json
├── public
├── README.md
├── src
│ ├── app
│ │ ├── app.component.css
│ │ ├── app.component.html
│ │ ├── app.component.spec.ts
│ │ ├── app.component.ts
│ │ ├── environment.ts
│ │ ├── index.ts
│ │ └── shared
│ │ └── index.ts
│ ├── favicon.ico
│ ├── index.html
│ ├── main.ts
│ ├── system-config.ts
│ ├── tsconfig.json
│ └── typings.d.ts
├── tslint.json
├── typings
│ └── ...
└── typings.json
現(xiàn)在,你可以運(yùn)行如下命令:
#切換到CLI剛剛為你創(chuàng)建的新目錄下
- $ cd angular2-todo-app
#啟動(dòng)開發(fā)服務(wù)器
- $ ng serve
上述命令將啟動(dòng)一個(gè)本地開發(fā)服務(wù)器,你可以在你的瀏覽器中導(dǎo)航到如下URL來(lái)觀察你的程序的初始界面:
http://localhost:4200/
使用Angular組件
當(dāng)我們使用ng new命令時(shí),Angular CLI已經(jīng)為我們生成整個(gè)Angular 2應(yīng)用程序的樣板內(nèi)容了。但它并非僅提供這些功能。它還可以幫助我們通過(guò)ng generate命令把其他對(duì)象添加到我們現(xiàn)有的Angular應(yīng)用程序中,命令如下:
- # Generate a new component
- $ ng generate component my-new-component
- # Generate a new directive
- $ ng generate directive my-new-directive
- # Generate a new pipe
- $ ng generate pipe my-new-pipe
- # Generate a new service
- $ ng generate service my-new-service
- # Generate a new class
- $ ng generate class my-new-class
- # Generate a new interface
- $ ng generate interface my-new-interface
- # Generate a new enum
- $ ng generate enum my-new-enum
【提示】如果您還不熟悉Angular 2程序中的基本模塊,特別推薦您先讀一下這篇文章(https://angular.io/docs/ts/latest/quickstart.html)。
為了滿足我們的Todo程序的需要,我們還需要實(shí)現(xiàn)如下功能:
創(chuàng)建一個(gè)Todo類來(lái)描述單個(gè)todo任務(wù)
創(chuàng)建一個(gè)TodoService服務(wù)來(lái)實(shí)現(xiàn)創(chuàng)建、更新和刪除已有的todo任務(wù)
開發(fā)一個(gè)TodoApp組件來(lái)顯示用戶界面
下面,讓我們一項(xiàng)一項(xiàng)地完成這些任務(wù)。
創(chuàng)建Todo類
因?yàn)槲覀兪褂玫氖荰ypeScript腳本語(yǔ)言,所以我們可以使用一個(gè)類來(lái)描述Todo任務(wù)項(xiàng)。我們可以通過(guò)Angular CLI命令來(lái)生成一個(gè)Todo類,命令如下:
- $ ng generate class Todo
上述命令將生成如下兩個(gè)文件:
src/app/todo.spec.ts
src/app/todo.ts
讓我們打開文件src/app/todo.ts,并使用如下內(nèi)容替換掉原來(lái)內(nèi)容:
- export class Todo {
- id: number;
- title: string = '';
- complete: boolean = false;
- constructor(values: Object = {}) {
- Object.assign(this, values);
- }
- }
每一個(gè)Todo項(xiàng)都有三個(gè)屬性:
id:數(shù)字類型,對(duì)應(yīng)于todo項(xiàng)的唯一的ID值
title:字符串類型,對(duì)應(yīng)于todo項(xiàng)的標(biāo)題
complete:布爾類型,指明當(dāng)前todo項(xiàng)是否已完成
接下來(lái),開始建立構(gòu)造函數(shù)代碼,從而允許我們?cè)趯?shí)例化過(guò)程中指定屬性值:
- let todo = new Todo({
- title: 'Read SitePoint article',
- complete: false
- });
注意,CLI已經(jīng)為我們生成了文件src/app/todo.spec.ts,所以我們可以添加一個(gè)單元測(cè)試來(lái)確保上述構(gòu)造器按我們的期望結(jié)果那樣工作:
- import {
- beforeEach, beforeEachProviders,
- describe, xdescribe,
- expect, it, xit,
- async, inject
- } from '@angular/core/testing';
- import {Todo} from './todo';
- describe('Todo', () => {
- it('should create an instance', () => {
- expect(new Todo()).toBeTruthy();
- });
- it('should accept values in the constructor', () => {
- let todo = new Todo({
- title: 'hello',
- complete: true
- });
- expect(todo.title).toEqual('hello');
- expect(todo.complete).toEqual(true);
- });
- });
為了驗(yàn)證我們的代碼是否按預(yù)期方式工作,我們現(xiàn)在可以運(yùn)行下面的單元測(cè)試命令:
- $ ng test
這個(gè)命令將運(yùn)行Karma程序(https://karma-runner.github.io/)來(lái)運(yùn)行上面我們創(chuàng)建的所有單元測(cè)試代碼。
目前,我們已經(jīng)有了一個(gè)Todo類。接下來(lái),我們要?jiǎng)?chuàng)建Todo服務(wù)來(lái)管理所有todo任務(wù)項(xiàng)。
創(chuàng)建TodoService服務(wù)
TodoService服務(wù)將負(fù)責(zé)管理我們的Todo項(xiàng)目。在以后的文章中,你將會(huì)看到我們?nèi)绾闻cREST API進(jìn)行通信;但現(xiàn)在,我們只是在內(nèi)存中存儲(chǔ)所有的數(shù)據(jù)。
讓我們?cè)俅问褂肁ngular CLI來(lái)生成我們的服務(wù):
- $ ng generate service Todo
生成內(nèi)容如下:
src/app/todo.service.spec.ts
src/app/todo.service.ts
現(xiàn)在,我們可以把todo管理邏輯添加到我們的TodoService了,內(nèi)容如下:
- import {Injectable} from '@angular/core';
- import {Todo} from './todo';
- @Injectable()
- export class TodoService {
- // Placeholder for last id so we can simulate
- // automatic incrementing of id's
- lastId: number = 0;
- // Placeholder for todo's
- todos: Todo[] = [];
- constructor() {
- }
- // Simulate POST /todos
- addTodo(todo: Todo): TodoService {
- if (!todo.id) {
- todo.id = ++this.lastId;
- }
- this.todos.push(todo);
- return this;
- }
- // Simulate DELETE /todos/:id
- deleteTodoById(id: number): TodoService {
- this.todos = this.todos
- .filter(todo => todo.id !== id);
- return this;
- }
- // Simulate PUT /todos/:id
- updateTodoById(id: number, values: Object = {}): Todo {
- let todo = this.getTodoById(id);
- if (!todo) {
- return null;
- }
- Object.assign(todo, values);
- return todo;
- }
- // Simulate GET /todos
- getAllTodos(): Todo[] {
- return this.todos;
- }
- // Simulate GET /todos/:id
- getTodoById(id: number): Todo {
- return this.todos
- .filter(todo => todo.id === id)
- .pop();
- }
- // Toggle todo complete
- toggleTodoComplete(todo: Todo){
- let updatedTodo = this.updateTodoById(todo.id, {
- complete: !todo.complete
- });
- return updatedTodo;
- }
- }
就本文目的而言,上述方法的具體實(shí)現(xiàn)細(xì)節(jié)并不至關(guān)重要。關(guān)鍵的內(nèi)容是我們要實(shí)現(xiàn)服務(wù)中的業(yè)務(wù)邏輯。
為了確保我們的邏輯按預(yù)期方式工作,讓我們向文件src/app/todo.service.spec.ts(已經(jīng)由CLI生成)添加單元測(cè)試。
因?yàn)锳ngular CLI已經(jīng)為我們生成了樣板代碼,所以我們只需要實(shí)現(xiàn)測(cè)試即可:
- import {
- beforeEach, beforeEachProviders,
- describe, xdescribe,
- expect, it, xit,
- async, inject
- } from '@angular/core/testing';
- import {Todo} from './todo';
- import {TodoService} from './todo.service';
- describe('Todo Service', () => {
- beforeEachProviders(() => [TodoService]);
- describe('#getAllTodos()', () => {
- it('should return an empty array by default', inject([TodoService], (service: TodoService) => {
- expect(service.getAllTodos()).toEqual([]);
- }));
- it('should return all todos', inject([TodoService], (service: TodoService) => {
- let todo1 = new Todo({title: 'Hello 1', complete: false});
- let todo2 = new Todo({title: 'Hello 2', complete: true});
- service.addTodo(todo1);
- service.addTodo(todo2);
- expect(service.getAllTodos()).toEqual([todo1, todo2]);
- }));
- });
- describe('#save(todo)', () => {
- it('should automatically assign an incrementing id', inject([TodoService], (service: TodoService) => {
- let todo1 = new Todo({title: 'Hello 1', complete: false});
- let todo2 = new Todo({title: 'Hello 2', complete: true});
- service.addTodo(todo1);
- service.addTodo(todo2);
- expect(service.getTodoById(1)).toEqual(todo1);
- expect(service.getTodoById(2)).toEqual(todo2);
- }));
- });
- describe('#deleteTodoById(id)', () => {
- it('should remove todo with the corresponding id', inject([TodoService], (service: TodoService) => {
- let todo1 = new Todo({title: 'Hello 1', complete: false});
- let todo2 = new Todo({title: 'Hello 2', complete: true});
- service.addTodo(todo1);
- service.addTodo(todo2);
- expect(service.getAllTodos()).toEqual([todo1, todo2]);
- service.deleteTodoById(1);
- expect(service.getAllTodos()).toEqual([todo2]);
- service.deleteTodoById(2);
- expect(service.getAllTodos()).toEqual([]);
- }));
- it('should not removing anything if todo with corresponding id is not found', inject([TodoService], (service: TodoService) => {
- let todo1 = new Todo({title: 'Hello 1', complete: false});
- let todo2 = new Todo({title: 'Hello 2', complete: true});
- service.addTodo(todo1);
- service.addTodo(todo2);
- expect(service.getAllTodos()).toEqual([todo1, todo2]);
- service.deleteTodoById(3);
- expect(service.getAllTodos()).toEqual([todo1, todo2]);
- }));
- });
- describe('#updateTodoById(id, values)', () => {
- it('should return todo with the corresponding id and updated data', inject([TodoService], (service: TodoService) => {
- let todo = new Todo({title: 'Hello 1', complete: false});
- service.addTodo(todo);
- let updatedTodo = service.updateTodoById(1, {
- title: 'new title'
- });
- expect(updatedTodo.title).toEqual('new title');
- }));
- it('should return null if todo is not found', inject([TodoService], (service: TodoService) => {
- let todo = new Todo({title: 'Hello 1', complete: false});
- service.addTodo(todo);
- let updatedTodo = service.updateTodoById(2, {
- title: 'new title'
- });
- expect(updatedTodo).toEqual(null);
- }));
- });
- describe('#toggleTodoComplete(todo)', () => {
- it('should return the updated todo with inverse complete status', inject([TodoService], (service: TodoService) => {
- let todo = new Todo({title: 'Hello 1', complete: false});
- service.addTodo(todo);
- let updatedTodo = service.toggleTodoComplete(todo);
- expect(updatedTodo.complete).toEqual(true);
- service.toggleTodoComplete(todo);
- expect(updatedTodo.complete).toEqual(false);
- }));
- });
- });
【提示】Karma工具中預(yù)配置了Jasmine(https://github.com/jasmine/jasmine),你可以閱讀資料http://jasmine.github.io/2.4/introduction.html來(lái)更多地了解有關(guān)它的語(yǔ)法。
為了校驗(yàn)我們編寫的業(yè)務(wù)邏輯都是有效的,讓我們?cè)賮?lái)運(yùn)行單元測(cè)試:
- $ ng test
現(xiàn)在,既然我們已經(jīng)有了一個(gè)可以使用的TodoService,那么接下來(lái)我們要實(shí)現(xiàn)程序的UI部分了。
值得注意的是,在Angular 2中,部分界面是使用組件(Components)來(lái)描述的。
創(chuàng)建TodoApp組件
讓我們?cè)僖淮问褂肅LI來(lái)生成我們所需要的程序組件吧:
- $ ng generate component TodoApp
上述命令生成內(nèi)容如下:
- src/app/todo-app/todo-app.component.css
- src/app/todo-app/todo-app.component.html
- src/app/todo-app/todo-app.component.spec.ts
- src/app/todo-app/todo-app.component.ts
- src/app/todo-app/index.ts
【提示】 模板和樣式可以在內(nèi)聯(lián)的腳本文件內(nèi)指定。默認(rèn)情況下,Angular的CLI將創(chuàng)建單獨(dú)的文件;所以,在這篇文章中我們也是使用單獨(dú)的文件。
接下來(lái),讓我們把組件的視圖添加到文件src/app/todo-app/todo-app.component.html中:
- <section class="todoapp">
- <header class="header">
- <h1>Todos</h1>
- <input class="new-todo" placeholder="What needs to be done?" autofocus="" [(ngModel)]="newTodo.title" (keyup.enter)="addTodo()">
- </header>
- <section class="main" *ngIf="todos.length > 0">
- <ul class="todo-list">
- <li *ngFor="let todo of todos" [class.completed]="todo.complete">
- <div class="view">
- <input class="toggle" type="checkbox" (click)="toggleTodoComplete(todo)" [checked]="todo.complete">
- <label>{{todo.title}}</label>
- <button class="destroy" (click)="removeTodo(todo)"></button>
- </div>
- </li>
- </ul>
- </section>
- <footer class="footer" *ngIf="todos.length > 0">
- <span class="todo-count"><strong>{{todos.length}}</strong> {{todos.length == 1 ? 'item' : 'items'}} left</span>
- </footer>
- </section>
在此,我們使用了Angular的超級(jí)短小的模板語(yǔ)法表達(dá)方式——而這是你以前從未遇到過(guò)的:
[property]="expression":把屬性設(shè)置為expression的結(jié)果
(event)=”statement”:當(dāng)事情發(fā)生時(shí)執(zhí)行statement
[(property)]="expression":使用expression創(chuàng)建雙向綁定
[class.special]="expression":當(dāng)expression為真時(shí)在元素上添加special類
[style.color]="expression":把css屬性color設(shè)置為expression的結(jié)果
【提示】如果你還不熟悉Angular的模板語(yǔ)法,那么你應(yīng)當(dāng)閱讀一下官方有關(guān)文檔,地址是https://angular.io/docs/ts/latest/guide/template-syntax.html。
下面,讓我們具體地看一下上面的代碼對(duì)我們的視圖的影響。首先,在頂部使用了一個(gè)Input控件來(lái)創(chuàng)建一個(gè)新的todo項(xiàng):
- <input class="new-todo" placeholder="What needs to be done?" autofocus="" [(ngModel)]="newTodo.title" (keyup.enter)="addTodo()">
在這里:
[(ngModel)]="newTodo.title":在input值與newTodo.title之間創(chuàng)建一個(gè)雙向綁定。
(keyup.enter)=”addTodo()”:在Input控件中輸入內(nèi)容并在按下回車時(shí)告訴Angular執(zhí)行addTodo()命令。
【提示】目前你先不用擔(dān)心newTodo和addTodo()的存在問(wèn)題,稍后會(huì)做這項(xiàng)工作?,F(xiàn)在,只需盡力弄懂視圖語(yǔ)義即可。
接下來(lái),使用一個(gè)節(jié)顯示todo部分:
- <section class="main" *ngIf="todos.length > 0">
其中,*ngIf="todos.length > 0"的含義是:當(dāng)至少有一個(gè)todo項(xiàng)時(shí),僅顯示section部分及其所有后代節(jié)點(diǎn)的內(nèi)容。
在該節(jié)中,我們要求Angular為每一個(gè)todo生成一個(gè)li元素:
- <li *ngFor="let todo of todos" [class.completed]="todo.complete">
其中:
*ngFor="let todo of todos":遍歷所有的todo并在每一次循環(huán)中把當(dāng)前todo賦值給一個(gè)命名為todo的變量。
[class.completed]="todo.complete":當(dāng)todo.complete為真時(shí)把CSS類completed應(yīng)用于元素li。
最后,我們通過(guò)ngFor循環(huán)顯示每一個(gè)todo項(xiàng)目的詳細(xì)信息:
- <div class="view">
- <input class="toggle" type="checkbox" (click)="toggleTodoComplete(todo)" [checked]="todo.complete">
- <label>{{todo.title}}</label>
- <button class="destroy" (click)="removeTodo(todo)"></button>
- </div>
在這里:
(click)="toggleTodoComplete(todo)":當(dāng)勾選復(fù)選框時(shí)執(zhí)行toggleTodoComplete(todo)
[checked]="todo.complete":把值todo.complete賦給元素的checked屬性
(click)="removeTodo(todo)":當(dāng)點(diǎn)擊刪除按鈕時(shí)執(zhí)行removeTodo(todo)
好,讓我們稍微喘口氣吧。到此我們已經(jīng)使用了不少新的語(yǔ)法格式。
你可能想知道像addTodo()和newTodo.title這樣的表達(dá)式是如何計(jì)算的。到目前,我們還沒(méi)有定義它們,那么Angular是如何理解我們的意圖的呢?
這正是表達(dá)式上下文(expression context)產(chǎn)生的原因。一個(gè)組件的表達(dá)式上下文就是組件實(shí)例。而組件實(shí)例就是組件類的一個(gè)實(shí)例。
我們的TodoAppComponent的組件類定義于文件src/app/todo-app/todo-app.component.ts中。
Angular CLI已經(jīng)為我們的TodoAppComponent類創(chuàng)建了模板,代碼如下:
- import { Component } from '@angular/core';
- @Component({
- moduleId: module.id,
- selector: 'app-todo-app',
- templateUrl: 'todo-app.component.html',
- styleUrls: ['todo-app.component.css']
- })
- export class TodoAppComponent {
- constructor() {}
- }
所以,我們可以馬上開始加入我們自定義的邏輯。我們將需要TodoService實(shí)例;因此,讓我們開始將它注入到我們的組件中。
首先,我們導(dǎo)入TodoService類,并在組件的修飾詞數(shù)組部分指定它:
- // Import class so we can register it as dependency injection token
- import {TodoService} from '../todo.service';
- @Component({
- // ...
- providers: [TodoService]
- })
- export class TodoAppComponent {
- // ...
- }
TodoAppComponent的依賴注入器現(xiàn)在能夠識(shí)別出TodoService類為依賴性注入符號(hào)并在我們要求時(shí)返回TodoService的單一實(shí)例。
【提示】Angular的依賴注入系統(tǒng)能夠接受各種各樣的依賴項(xiàng)注入。上述語(yǔ)法只是類提供器(Class Provider:使用單例模式提供依賴性)格式的一個(gè)速記表示。有關(guān)此內(nèi)容更多的細(xì)節(jié),請(qǐng)參考官方的網(wǎng)址https://angular.io/docs/ts/latest/guide/dependency-injection.html。
現(xiàn)在,組件的依賴注入器知道它需要提供什么了,我們要求它通過(guò)在TodoAppComponent構(gòu)造函數(shù)中指定依賴項(xiàng)來(lái)在我們的組件中注入TodoService實(shí)例:
- // Import class so we can use it as dependency injection token in the constructor
- import {TodoService} from '../todo.service';
- @Component({
- // ...
- })
- export class TodoAppComponent {
- // Ask Angular DI system to inject the dependency
- // associated with the dependency injection token `TodoService`
- // and assign it to a property called `todoService`
- constructor(private todoService: TodoService) {
- }
- // Service is now available as this.todoService
- toggleTodoComplete(todo) {
- this.todoService.toggleTodoComplete(todo);
- }
- }
現(xiàn)在,我們可以實(shí)現(xiàn)我們的視圖中需要的所有邏輯了。為此,只需要向我們 TodoAppComponent類中添加屬性和方法就可以了:
- import {Component} from '@angular/core';
- import {Todo} from '../todo';
- import {TodoService} from '../todo.service';
- @Component({
- moduleId: module.id,
- selector: 'todo-app',
- templateUrl: 'todo-app.component.html',
- styleUrls: ['todo-app.component.css'],
- providers: [TodoService]
- })
- export class TodoAppComponent {
- newTodo: Todo = new Todo();
- constructor(private todoService: TodoService) {
- }
- addTodo() {
- this.todoService.addTodo(this.newTodo);
- this.newTodo = new Todo();
- }
- toggleTodoComplete(todo) {
- this.todoService.toggleTodoComplete(todo);
- }
- removeTodo(todo) {
- this.todoService.deleteTodoById(todo.id);
- }
- get todos() {
- return this.todoService.getAllTodos();
- }
- }
當(dāng)組件類實(shí)例化時(shí),我們首先實(shí)例化一個(gè)newTodo屬性并分配新的Todo()。下面的代碼展示了在我們的視圖中添加的雙向綁定到的newTodo:
- <input class="new-todo" placeholder="What needs to be done?" autofocus="" [(ngModel)]="newTodo.title" (keyup.enter)="addTodo()">
無(wú)論視圖中的輸入值何時(shí)改變,組件實(shí)例中的值都被更新。而無(wú)論組件實(shí)例中的輸入值何時(shí)改變,視圖中的輸入元素中的值都將更改。
接下來(lái),我們要實(shí)現(xiàn)我們的視圖中使用的所有方法。
它們的具體實(shí)現(xiàn)代碼很短,應(yīng)該是不需要給予過(guò)多解釋的,因?yàn)槲覀円呀?jīng)把所有業(yè)務(wù)邏輯委派到todoService了。
【提示】把業(yè)務(wù)邏輯委派到一個(gè)專門的服務(wù)中是一種良好的編程實(shí)踐,因?yàn)樗刮覀兡軌蚣芯芾砗蜏y(cè)試業(yè)務(wù)邏輯。
最后,在結(jié)束本教程前,讓我們來(lái)了解一下Angular CLI的最后一個(gè)很酷的功能吧。
部署到GitHub網(wǎng)站
Angular的CLI使得將我們的應(yīng)用部署到GitHub頁(yè)變得超級(jí)簡(jiǎn)單——使用類似于下面的這樣一個(gè)命令即可搞定:
- $ ng github-pages:deploy --message 'deploy(dist): deploy on GitHub pages'
這個(gè)github-pages:deploy命令告訴Angular CLI生成我們的Angular應(yīng)用的一個(gè)靜態(tài)版本,并將它推送到我們的GitHub倉(cāng)庫(kù)的gh-pages分支下。相應(yīng)的輸出結(jié)果如下所示:
- $ ng github-pages:deploy --message 'deploy(dist): deploy on GitHub pages'
- Built project successfully. Stored in "dist/".
- Deployed! Visit https://sitepoint-editors.github.io/angular2-todo-app/
- Github pages might take a few minutes to show the deployed site.
現(xiàn)在,我們的應(yīng)用程序可以通過(guò)網(wǎng)站地址https://sitepoint-editors.github.io/angular2-todo-app/進(jìn)行訪問(wèn)了。
趕快去打開這個(gè)網(wǎng)址去試試吧。
小結(jié)
Angular 2無(wú)疑是一只猛獸!一只非常強(qiáng)大的猛獸!
在本文中,我向你介紹了很多很多?,F(xiàn)在,讓我們回顧一下我們?cè)谶@篇文章中所學(xué)到的內(nèi)容吧:
我們學(xué)習(xí)了如何安裝Angular CLI并了解了在創(chuàng)建新的應(yīng)用程序或添加現(xiàn)有應(yīng)用程序的新特征時(shí)它如何節(jié)約我們的時(shí)間。
我們學(xué)習(xí)了如何在一個(gè)Angular服務(wù)中實(shí)現(xiàn)業(yè)務(wù)邏輯以及如何使用單元測(cè)試來(lái)測(cè)試我們的業(yè)務(wù)邏輯。
我們學(xué)習(xí)了如何使用組件與用戶交互以及如何使用依賴注入委派邏輯到服務(wù)中。
我們學(xué)習(xí)了Angular模板語(yǔ)法基礎(chǔ)知識(shí),并簡(jiǎn)要地談?wù)摿薃ngular依賴項(xiàng)注入的工作原理。
最后,我們學(xué)習(xí)了如何把我們的應(yīng)用程序快速部署到GitHub網(wǎng)頁(yè)。
在以后的文章中,我們還有很多有關(guān)Angular 2的內(nèi)容探討,例如:
使用Angular 2 HTTP服務(wù)與REST API后端進(jìn)行通信
使用Angular管道功能過(guò)濾todo內(nèi)容
通過(guò)路由來(lái)使本文中的應(yīng)用變成一個(gè)多頁(yè)式應(yīng)用程序
以及其他更多更多……
所以,敬請(qǐng)期待更多的關(guān)于Angular 2這個(gè)奇妙的世界吧。