angular2初入眼簾之-瞭解component

前集回顧html

上一章裏咱們講了如何爲angular2搭建開發環境(還沒搭起來的趕忙去看哦),並使之跑起來咱們的第一個"My First Angular 2 App"。固然也有很多朋友反映環境搭建彷佛比較複雜,整整一篇教程,最後只簡單輸出了一句話!這裏我要說一句,學習新知識的確有一個陣痛的過程,尤爲像angular2這種框架,引入了大量之前"前端"並不關心(沒有需求)的技術棧,這使得對於以前沒有接觸過這些概念的朋友的學習曲線陡然飆升,相信很多人看了上一章裏開篇時的那些名詞後已經認識到這一點了!本教程主打實際操做,但也不會徹底忽略理論,咱們邊作邊理解。今天就接着上一章的餘溫,咱們來寫一個簡單component前端

本章源碼:componentwebpack

本章使用angular2版本爲:2.4.5, webpack版本爲: 2.2.0git

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

圖片描述

(注意動畫的部分)很是簡單的一個component,有木有?那好,咱們如今要作的就是爲這樣一個component描述需求:es6

  1. 她要能接受一個object用來描述初始值,如:isChecked(是否選中)、 txt(顯示文本)github

  2. 當選中時,須要有橫線覆蓋文本;反之亦然web

  3. 當用戶點擊複選框時,須要向上廣播該事件,由父組件(調用方)決定點擊時該作什麼。這裏咱們須要在父組件裏改變componentisChecked狀態,並使component重繪typescript

  4. 她必須是一個處理Unidirectional Data Flow(單向數據流)的component,意思是傳入參數必須不可變(Immutable)shell

注:第4步裏,咱們使用Unidirectional Data Flow模型來更新數據,並無涉及到任何Reactive Programming的知識點

爲了完成以上需求,咱們須要瞭解下面知識點

什麼是component

或者這麼問,AngularJS裏有directiveangular2裏有component,他們是什麼關係?該如何理解angular2裏的component?原諒我這裏就再也不詳述AngularJS裏的directive了,直接介紹component

  1. Component: 簡單說,就是帶templatedirective,也是最多見的組件形式。譬如:上一章中,ts/app.ts裏的AppComponent

  2. Structural directive: 經過增長/刪除DOM元素改變DOM佈局的directive。譬如:NgForNgIf

  3. Attribute directive: 控制DOM元素顯示/隱藏,或者改變元素行爲的directive。譬如:NgStyle

設計use case

看過我以前介紹以BDD手寫依賴注入(dependency injection)的朋友應該已經對"行爲驅動"多少有些瞭解了。當咱們須要設計一個API或者組件時,最佳的方式就是先設計她的使用場景,從行爲開始,對該API或者組件進行描述,最後再將缺失的「實現」部分補全就能夠了。

假設咱們將在上一章中的AppComponent裏使用這個新的component,根據以前的需求描述,咱們的使用場景應該是這個樣子的 :

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

import {Item} from './CheckableItem';

//該component使用checkable-item做爲selector
//並能夠經過[item]屬性傳入一個object
//還能夠經過(onItemClicked)接受一個點擊事件
@Component({
    selector: 'my-app',
    template: `
    <h1>My First Angular 2 App</h1>
    <checkable-item [item]="itemInfo" (onItemClicked)="toggle($event)">
    </checkable-item>
    `
})
export class AppComponent implements OnInit {

    itemInfo: Item;

    //當實現OnInit接口時,必須重寫ngOnInit方法
    //關於OnInit,詳見:
    //https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html#!#hooks-overview
    ngOnInit() {
        //設定初始值
        //根據需求第1條,包含兩個屬性
        this.itemInfo = {
            isChecked: false,
            txt: 'Hello World!'
        };
    }

    //根據需求第3條,點擊component後,事件要
    //冒泡到父組件(調用方)
    toggle(item: Item) {
        //當獲取到CheckableItem的點擊事件時,
        //給itemInfo從新賦值,並將isChecked置反
        //注:從新賦值是根據需求第4條的不可變性
        this.itemInfo = {
            isChecked: !item.isChecked,
            txt: item.txt
        };
    }
}

實現component

根據上述介紹,再結合以前的效果圖,咱們要作的固然就是一個標準的Component。她有template,而且包含了至少一個input和一個label標籤。

有了使用場景(行爲),接下來就是實現這個CheckableItem了:

touch ts/CheckableItem.ts

向剛建立的ts/CheckableItem.ts文件裏寫入以下內容:

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

@Component({
    //髒檢查策略,OnPush指當且僅當傳入參數的reference發生變動時
    //觸發組件重繪。這和React中的shouldComponentUpdate殊途同歸,
    //不過更先進(由於React仍是須要手動實現的)
    //這也是上一步裏itemInfo必須從新賦值的緣由
    changeDetection: ChangeDetectionStrategy.OnPush,
    selector: 'checkable-item',
    //僅在當前component做用域下有效的class
    styles: [`
        .deleted{
            text-decoration: line-through;
        }
    `],
    //template就如咱們需求裏的描述那樣,由一個input標籤和
    //一個label標籤組成
    template: `
    <div>
        <input type="checkbox" (change)="clickItem($event)">
        <label [class.deleted]="item.isChecked">{{ item.txt }}</label>
    </div>
    `
})
export class CheckableItem {
    //item被聲明爲Input,即會在父組件傳入參數時用到
    @Input() item: Item;
    //onItemClicked被聲明爲Output,用來在用戶點擊input標籤
    //時向上冒泡事件
    @Output() onItemClicked = new EventEmitter();

    //監聽input上的click事件,當用戶點擊時,首先阻止默認行爲
    //由於是否變化(重繪)是由父組件決定的
    //而後冒泡點擊事件
    clickItem(e: MouseEvent) {
        e.preventDefault();
        this.onItemClicked.emit(this.item);
    }
}


export interface ToggleItemHandler {
    (item: Item): void;
}

export interface Item {
    isChecked?: boolean;
    txt?: string;
}

有朋友看到這裏,對[]()之類的綁定標籤表示不解,這裏咱們統一來解釋:

  1. [target] = "expression",將右邊表達式對應的值綁定到左邊的target。譬如:在ts/app.ts裏,咱們使用[item]="itemInfo"itemInfo對應的值綁定到了組件CheckableItemitem上,這樣,在CheckableItem裏就能夠經過this.item獲取到父組件傳進來的參數了。

  2. (target) = "statement",將左邊的事件傳遞給了右邊的表達式(一般就是事件處理函數)。譬如:在ts/app.ts裏,咱們使用(onItemClicked)="toggle($event)"CheckableItem冒泡上來的onItemClicked事件傳遞給了toggle函數。

  3. [class.deleted]="item.isChecked",是class的一種特殊用法,指當item.isChecked表達式爲真時,爲該標籤的class裏增長deleted;反之,則刪除該標籤class裏的deleted

引入聲明

打開以前寫的index.ts,增長CheckableItem引入:

import 'core-js/es6';
import 'core-js/es7/reflect';
import 'zone.js/dist/zone';

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent }  from './app';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

//引入CheckableItem
import {CheckableItem} from './CheckableItem';

@NgModule({
  imports:      [ BrowserModule ],
  declarations: [ AppComponent, CheckableItem ],//引入聲明
  bootstrap:    [ AppComponent ]
})
class AppModule { }

platformBrowserDynamic().bootstrapModule(AppModule);

見證奇蹟

OK,事已至此,咱們是否是又該啓動一把程序看看效果了?

npm start

你又看到了偉大的效果:

圖片描述

下回預告:小刀升級 - 多component協做

相關文章
相關標籤/搜索