angular2初入眼簾之-service

前集回顧webpack

上一章裏咱們在AppComponent裏經過組合InputItemCheckableItemCounter三個組件,並經過Unidirectional Data Flow(單向數據流)的方式把她們驅動起來。今天這章,咱們講講angular2裏的servicegit

本章源碼:servicegithub

本章使用angular2版本爲:2.4.5webpack版本爲: 2.2.0web

先來看看咱們將要完成的效果圖:typescript

圖片描述

需求分析

(注意動畫部分),在上一章的基礎上咱們加入了初始化數據,在數據加載完成前會有一個loading,數據準備好以後loading消失,列表顯現。shell

設計use case

每章都會提一下,先設計使用場景(這種方式,咱們稱之爲"BDD",不瞭解的朋友參考以BDD手寫依賴注入(dependency injection))。npm

重構ts/app.ts

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

import {Item} from './CheckableItem';

//引入本章主題ItemService
import {ItemService} from './ItemService';

@Component({
    selector: 'my-app',
    template: `
    <h1>My First Angular 2 App</h1>
    <input-item (onItemAdded)="addItem($event)"></input-item>
    <checkable-item *ngFor="let itemInfo of items; let i = index" [item]="itemInfo" (onItemClicked)="toggle($event, i)">
    </checkable-item>
    <p *ngIf="loading">Loading</p>
    <counter *ngIf="!loading" [items]="items"></counter>
    `,
    directives: [InputItem, CheckableItem, Counter],
    //注入ItemService
    providers: [ItemService]
})
export class AppComponent implements OnInit {

    items: Item[] = [];
    //聲明loading狀態,初始值爲true
    loading: boolean = true;

    //經過構造器自動獲取ItemService實例
    constructor(private _itemService: ItemService) { }

    //在組件初始化之後調用ItemService獲取初始化數據
    ngOnInit() {
        this._itemService
            .getItems()
            .then(data => {
                //重置loading狀態爲false
                this.loading = false;
                //設置初始值
                this.items = data;
            });
    }

    addItem(item: Item) {
        this.items = [...this.items, item];
    }

    toggle(item: Item, index: number) {
        this.items = [
            ...this.items.slice(0, index),
            { isChecked: !item.isChecked, txt: item.txt },
            ...this.items.slice(index + 1)
        ];
    }
}

實現ItemService

touch ts/ItemService.ts

向剛建立的ts/ItemService.ts中,添加以下內容:segmentfault

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

import {Item} from './CheckableItem';

//用Injectable裝飾器聲明該類可被依賴注入
@Injectable()
export class ItemService {

    //設置一個初始值數組
    private items: Item[] = [
        {
            isChecked: true,
            txt: 'Learn JavaScript'
        }, {
            isChecked: false,
            txt: 'Learn TypeScript'
        }, {
            isChecked: false,
            txt: 'Learn Angular2'
        }
    ];

    //提供一個方法,返回初始數據的Promise
    getItems(): Promise<Array<Item>> {
        return new Promise((resolve, reject) => {
            //這裏手動作延遲是爲了模擬網絡請求
            setTimeout(() => {
                resolve(this.items);
            }, 1500);
        });
    }
}

查看效果

本章內容比較簡單,寫到這裏差很少算結束了(其實尚未哦!),先來跑跑看數組

npm start

OK,我確信這個代碼是能夠運行的,那到底什麼是service?咱們如今來對着代碼講一講。網絡

什麼是service

  • service是可被替換的

  • service必須經過依賴注入使用

  • service一般用做數據存取等應用中可公用邏輯部分

如何定義service

必須經過@Injectable裝飾器聲明

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

@Injectable()
export class ItemService {
}

使用service

引入service

import {ItemService} from './ItemService';

切忌不要自做多情的new她哦!!!!!

構造器獲取實例

constructor(private _itemService: ItemService) { }

自動注入實例

就像directives那樣,添加到@Component的metadata中

providers: [ItemService]

就這麼簡單,so easy 有木有?

圖片描述

重構

那麼咱們說,到這裏就結束了嗎?請看下面,template裏有這麼一段:

圖片描述

  • 用了*ngForitems列表化

  • 用了*ngIf控制loading的顯示狀態

是否是感受有點兒矬了,若是能有個單獨的ItemList組件該多好?像這樣使用:

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

import {Item} from './CheckableItem';

import {ItemService} from './ItemService';

@Component({
    selector: 'my-app',
    template: `
    <h1>My First Angular 2 App</h1>
    <input-item (onItemAdded)="addItem($event)"></input-item>
    <item-list [data]="items" (onItemClicked)="toggle($event)" [showLoading]="loading">
    </item-list>
    <counter *ngIf="!loading" [items]="items"></counter>
    `,
    providers: [ItemService]
})
export class AppComponent implements OnInit {

    items: Item[] = [];
    loading: boolean = true;

    constructor(private _itemService: ItemService) { }

    ngOnInit() {
        this._itemService
            .getItems()
            .then(data => {
                this.loading = false;
                this.items = data;
            });
    }

    addItem(item: Item) {
        this.items = [...this.items, item];
    }

    toggle(e: { item: Item, index: number }) {
        this.items = [
            ...this.items.slice(0, e.index),
            { isChecked: !e.item.isChecked, txt: e.item.txt },
            ...this.items.slice(e.index + 1)
        ];
    }
}

實現ItemList

touch ts/ItemList.ts

向剛建立的ts/ItemList.ts中,添加以下內容:

import {Component, Input, Output, EventEmitter, ChangeDetectionStrategy} from '@angular/core';

import { Item } from './CheckableItem';

@Component({
    changeDetection: ChangeDetectionStrategy.OnPush,
    selector: 'item-list',
    template: `
    <checkable-item *ngFor="let item of data; let i=index" [item]="item" (onItemClicked)="clickItem($event, i)">
    </checkable-item>
    <p *ngIf="showLoading">Loading</p>
    `
})
export class ItemList {
    @Input() data: Item[];
    @Input() showLoading: boolean;

    @Output() onItemClicked = new EventEmitter();

    clickItem(e: Item, i: number) {
        this.onItemClicked.emit({
            item: e,
            index: i
        });
    }
}

一切都結束了,效果仍然沒有變,仍是很屌的樣子!!!!

下回預告:使用Routing

相關文章
相關標籤/搜索