angular2初入眼帘之-多components协作
前集回顧
在上一章里我們講了如何在angular2下開發一個component(還沒做的趕緊去學吧)。我們使用了Unidirectional Data Flow模式書寫component,并引入了Immutable思想,這些以前只在React里見到的設計,現在angular2里也有體現,并且在本章中會著重講解多components的協作。
本章源碼:multicomponents
本章使用angular2版本為:2.4.5,webpack版本為: 2.2.0
先來看看我們將要完成的效果圖:
需求分析
(注意動畫部分),由上一章的一個component,變成了一個輸入component、 一個遍歷顯示component、 一個總結component。畫一個組件樹的示意圖如下:
圖片描述
分析第一部分
我們將其命名為InputItem
它由一個input[type="text"]和一個button組成
當點擊button時,需要向上冒泡事件,并組合一個新的CheckableItem隨事件發送出去
清空input[type="text"]
第3步操作,也可以通過鍵盤敲擊"回車鍵"完成操作
分析第二個遍歷顯示部分
參考上一章
關于*ngFor
分析第三個總結部分
我們將其命名為Counter
它由一個span組成,顯示總結信息
它接受一個items參數,用來生成總結信息
總結信息為:顯示當前還有多少個isChecked === false的item
設計use case
還是老套路,先來設計這些新的components的使用場景(這種方式,我們稱之為"BDD",不了解的朋友參考以BDD手寫依賴注入。
重構ts/app.ts
import {Component} from '@angular/core';import {Item} from './CheckableItem';@Component({selector: 'my-app',template: `<h1>My First Angular 2 App</h1><!--在template里,增加input-item和counter的使用input-item里,捕獲onItemAdded事件,傳遞給addItem方法--><input-item (onItemAdded)="addItem($event)"></input-item><!--使用*ngFor遍歷items變量。詳情:https://angular.io/docs/ts/latest/guide/template-syntax.html#!#ngFor--><checkable-item *ngFor="let itemInfo of items; let i = index" [item]="itemInfo" (onItemClicked)="toggle($event, i)"></checkable-item><!--counter里,傳入items--><counter [items]="items"></counter>` }) export class AppComponent {//聲明items為成員變量items: Item[] = [];//當捕獲到onItemAdded事件時,調用該方法,添加新item到items里//注:根據Immutable策略,生成新的itemsaddItem(item: Item) {this.items = [...this.items, item];}//點擊checkable-item時,置反其isChecked屬性//注:根據Immutable策略,生成新的itemstoggle(item: Item, index: number) {this.items = [...this.items.slice(0, index),{ isChecked: !item.isChecked, txt: item.txt },...this.items.slice(index + 1)];} }實現InputItem
touch ts/InputItem.ts向剛創建的ts/InputItem.ts中,添加如下內容:
import {Component, Output, EventEmitter, ChangeDetectionStrategy} from '@angular/core';@Component({//這里仍然使用OnPush策略changeDetection: ChangeDetectionStrategy.OnPush,selector: 'input-item',//template里包含一個input[type="text"]和button//外面又一個form標簽是因為需求中希望回車鍵也可以觸發操作template: `<form (ngSubmit)="onSubmit()"><input type="text" [(ngModel)]="text" name="todo"><button type="submit">Add Item</button></form>` }) export class InputItem {//雙向綁定到input[type="text"]text: string;//向外部冒泡的事件@Output() onItemAdded = new EventEmitter();//無論點擊button、還是敲擊回車鍵,都處罰添加事件//組裝一個新的item對象,//清空textonSubmit() {this.onItemAdded.emit({isChecked: false,txt: this.text});this.text = '';} }實現Counter
touch ts/Counter.ts向剛創建的ts/Counter.ts中,添加如下內容:
import {Component, OnChanges, SimpleChange, Input, ChangeDetectionStrategy} from '@angular/core';import {Item} from './CheckableItem';@Component({//這里仍然使用OnPush策略changeDetection: ChangeDetectionStrategy.OnPush,selector: 'counter',//template包含一個spantemplate: `<span>We have {{ length }} item{{ postFix }}</span>` }) export class Counter implements OnChanges {//接受items參數@Input() items: Item[];postFix: string;length: number;//每次當參數items的reference發生變化時,觸發該方法//獲取新的length、postFix,重繪組件//這里和React中的componentWillUpdate很相似ngOnChanges(changes: { [key: string]: SimpleChange }): any {let newItems: Item[] = changes['items'].currentValue;this.length = newItems.reduce((p, item) => p + (item.isChecked ? 0 : 1), 0);this.postFix = this.length > 1 ? 's' : '';} }修改CheckableItem
import {Component, Input, Output, EventEmitter, ChangeDetectionStrategy} from '@angular/core';@Component({changeDetection: ChangeDetectionStrategy.OnPush,selector: 'checkable-item',styles: [`.deleted{text-decoration: line-through;}`],template: `<div><input type="checkbox" [checked]="item.isChecked" (change)="clickItem($event)"><label [class.deleted]="item.isChecked">{{ item.txt }}</label></div>` }) export class CheckableItem {@Input() item: Item;@Output() onItemClicked = new EventEmitter();clickItem(e: MouseEvent) {e.preventDefault();this.onItemClicked.emit(this.item);} }export interface ToggleItemHandler {(item: Item): void; }export interface Item {isChecked?: boolean;txt?: string; }組件樹的整體編寫思路就是Unidirectional Data Flow,所以數據的變更都是Immutable的。如果之前寫過React,那對于這種書寫方式一定無比熟悉。每次數據的變更,無論是InputItem還是CheckableItem,都將變化冒泡到AppComponent,然后由AppComponent再向下逐級推送各組件是否重繪。
引入聲明
打開index.ts,增加新模塊聲明引入
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 { FormsModule } from '@angular/forms'; import { AppComponent } from './app'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';import {CheckableItem} from './CheckableItem'; import {InputItem} from './InputItem'; import {Counter} from './Counter';@NgModule({imports: [ BrowserModule, FormsModule ],declarations: [ AppComponent, CheckableItem, InputItem, Counter ],bootstrap: [ AppComponent ] }) class AppModule { }platformBrowserDynamic().bootstrapModule(AppModule);OK,代碼寫到這里基本就結束了,看看效果吧
npm start你又看到了偉大的效果:
下回預告:使用service
總結
以上是生活随笔為你收集整理的angular2初入眼帘之-多components协作的全部內容,希望文章能夠幫你解決所遇到的問題。