前集回忆
在上一章里我们讲了如安在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步操纵,也能够经由过程键盘敲击”回车键”完成操纵
剖析第二个遍历显现部份
剖析第三个总结部份
我们将其命名为
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战略,天生新的items
addItem(item: Item) {
this.items = [...this.items, item];
}
//点击checkable-item时,置反其isChecked属性
//注:依据Immutable战略,天生新的items
toggle(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对象,
//清空text
onSubmit() {
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包括一个span
template: `
<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