在Quick Start的基础上继续,复制angular2-quickstart
文件夹并重命名为angular2-tour-of-heroes
。进入文件夹运行npm start
看是否可以正常运行。
cp -r angular2-quickstart angular2-tour-of-heroes
cd angular2-tour-of-heroes
npm start
向AppComponent
添加两个属性:
export class AppComponent {
public title = 'Tour of Heroes';
public hero = 'Windstorm';
}
更新模板:
template: '<h1>{{title}}</h1><h2>{{hero}} details!</h2>'
浏览器会自动刷新,显示结果如下:
上面的hero
只是个字符串,如果需要更多属性,可以将它改成interface,定义interface的代码要写在使用它的代码之前:
interface Hero {
id: number;
name: string;
}
PS:怎样确定对象的定义是选择Interface还是Class呢?如果对象除了属性还有其他的逻辑和行为,那么就必须定义为Class,如果只需要类型检查,那么Interface更轻量级。
接下来将组件的hero
属性改成Hero
类型:
public hero: Hero = {
id: 1,
name: 'Windstorm'
};
模板中的绑定也要修改,而且可以现实更多hero
的信息了:
template:`
<h1>{{title}}</h1>
<h2>{{hero.name}} details!</h2>
<div><label>id: </label>{{hero.id}}</div>
<div><label>name: </label>{{hero.name}}</div>
`
PS:多行字符串可以使用反引号。
浏览器中显示如下:
添加一个文本框用于编辑Hero的姓名。
template:`
<h1>{{title}}</h1>
<h2>{{hero.name}} details!</h2>
<div><label>id: </label>{{hero.id}}</div>
<div>
<label>name: </label>
<div><input value="{{hero.name}}" placeholder="name"></div>
</div>
`
这样浏览器中会将hero的姓名放到文本框中,但是有点奇怪的是,改变文本框中的值,<h2>
中的hero.name并不会改变,因为这里文本框用的是单向数据绑定。将文本框改成双向绑定:
<input [(ngModel)]="hero.name" placeholder="name">
浏览器中显示如下:
至此,app.conpoment.ts文件内容如下:
import {Component} from 'angular2/core';
interface Hero {
id: number;
name: string;
}
@Component({
selector: 'my-app',
template:`
<h1>{{title}}</h1>
<h2>{{hero.name}} details!</h2>
<div><label>id: </label>{{hero.id}}</div>
<div>
<label>name: </label>
<div><input [(ngModel)]="hero.name" placeholder="name"></div>
</div>
`
})
export class AppComponent {
public title = 'Tour of Heroes';
public hero: Hero = {
id: 1,
name: 'Windstorm'
};
}
在文件app.component.ts
的最后定义一个heroes数组:
var HEROES: Hero[] = [
{ "id": 11, "name": "Mr. Nice" },
{ "id": 12, "name": "Narco" },
{ "id": 13, "name": "Bombasto" },
{ "id": 14, "name": "Celeritas" },
{ "id": 15, "name": "Magneta" },
{ "id": 16, "name": "RubberMan" },
{ "id": 17, "name": "Dynama" },
{ "id": 18, "name": "Dr IQ" },
{ "id": 19, "name": "Magma" },
{ "id": 20, "name": "Tornado" }
];
在AppComponent组件中添加一个共有属性:
public heroes = HEROES;
在模板中添加一个无序列表来显示hero数组,使用ngFor
指令将heroes数组绑定到模板:
<h2>My Heroes</h2>
<ul class="heroes">
<li *ngFor="#hero of heroes">
<span class="badge">{{hero.id}}</span> {{hero.name}}
</li>
</ul>
在@Component
中设置style
属性来添加样式,完整的app.component.ts文件内容如下:
import {Component} from 'angular2/core';
interface Hero {
id: number;
name: string;
}
@Component({
selector: 'my-app',
template:`
<h1>{{title}}</h1>
<h2>{{hero.name}} details!</h2>
<div><label>id: </label>{{hero.id}}</div>
<div>
<label>name: </label>
<div><input [(ngModel)]="hero.name" placeholder="name"></div>
</div>
<h2>My Heroes</h2>
<ul class="heroes">
<li *ngFor="#hero of heroes">
<span class="badge">{{hero.id}}</span> {{hero.name}}
</li>
</ul>
`,
styles:[`
.selected {
background-color: #CFD8DC !important;
color: white;
}
.heroes {
margin: 0 0 2em 0;
list-style-type: none;
padding: 0;
width: 10em;
}
.heroes li {
cursor: pointer;
position: relative;
left: 0;
background-color: #EEE;
margin: .5em;
padding: .3em 0;
height: 1.6em;
border-radius: 4px;
}
.heroes li.selected:hover {
background-color: #BBD8DC !important;
color: white;
}
.heroes li:hover {
color: #607D8B;
background-color: #DDD;
left: .1em;
}
.heroes .text {
position: relative;
top: -3px;
}
.heroes .badge {
display: inline-block;
font-size: small;
color: white;
padding: 0.8em 0.7em 0 0.7em;
background-color: #607D8B;
line-height: 1em;
position: relative;
left: -1px;
top: -4px;
height: 1.8em;
margin-right: .8em;
border-radius: 4px 0 0 4px;
}
`]
})
export class AppComponent {
public title = 'Tour of Heroes';
public hero: Hero = {
id: 1,
name: 'Windstorm'
};
public heroes = HEROES;
}
var HEROES: Hero[] = [
{ "id": 11, "name": "Mr. Nice" },
{ "id": 12, "name": "Narco" },
{ "id": 13, "name": "Bombasto" },
{ "id": 14, "name": "Celeritas" },
{ "id": 15, "name": "Magneta" },
{ "id": 16, "name": "RubberMan" },
{ "id": 17, "name": "Dynama" },
{ "id": 18, "name": "Dr IQ" },
{ "id": 19, "name": "Magma" },
{ "id": 20, "name": "Tornado" }
];
浏览器中显示如下:
目前heroes数组和显示的单个hero信息是没有关联的。接下来要实现的效果是,选择heroes列表中的一个hero后,显示他的详细信息。为组件添加selectedHero
属性并绑定事件。
修改<li>
,添加点击事件绑定:
<li *ngFor="#hero of heroes" (click)="onSelect(hero)">
<span class="badge">{{hero.id}}</span> {{hero.name}}
</li>
将组件的hero
属性替换成selectedHero
,并且添加点击事件的处理:
selectedHero: Hero;
onSelect(hero: Hero) { this.selectedHero = hero; }
将模板中对原来的属性hero
的引用改成selectedHero
:
<h2>{{selectedHero.name}} details!</h2>
<div><label>id: </label>{{selectedHero.id}}</div>
<div>
<label>name: </label>
<input [(ngModel)]="selectedHero.name" placeholder="name"/>
</div>
当应用启动时,并没有选中的hero,这时selectedHero
是undefined
。将详细信息放入<div>
中,并使用ngIf
指令,这样当selectedHero
为undefined
时就不显示该<div>
:
<div *ngIf="selectedHero">
<h2>{{selectedHero.name}} details!</h2>
<div><label>id: </label>{{selectedHero.id}}</div>
<div>
<label>name: </label>
<input [(ngModel)]="selectedHero.name" placeholder="name"/>
</div>
</div>
为选中项添加样式:
<li *ngFor="#hero of heroes"
[class.selected]="hero === selectedHero"
(click)="onSelect(hero)">
<span class="badge">{{hero.id}}</span> {{hero.name}}
</li>
[class.selected]="hero === selectedHero"
的意思是,当该项hero与selectedHero相等时,就使用.selected
样式。
完整的app.component.ts文件内容如下:
import {Component} from 'angular2/core';
interface Hero {
id: number;
name: string;
}
@Component({
selector: 'my-app',
template:`
<h1>{{title}}</h1>
<h2>My Heroes</h2>
<ul class="heroes">
<li *ngFor="#hero of heroes"
[class.selected]="hero === selectedHero"
(click)="onSelect(hero)">
<span class="badge">{{hero.id}}</span> {{hero.name}}
</li>
</ul>
<div *ngIf="selectedHero">
<h2>{{selectedHero.name}} details!</h2>
<div><label>id: </label>{{selectedHero.id}}</div>
<div>
<label>name: </label>
<input [(ngModel)]="selectedHero.name" placeholder="name"/>
</div>
</div>
`,
styles:[`
.selected {
background-color: #CFD8DC !important;
color: white;
}
.heroes {
margin: 0 0 2em 0;
list-style-type: none;
padding: 0;
width: 10em;
}
.heroes li {
cursor: pointer;
position: relative;
left: 0;
background-color: #EEE;
margin: .5em;
padding: .3em 0;
height: 1.6em;
border-radius: 4px;
}
.heroes li.selected:hover {
background-color: #BBD8DC !important;
color: white;
}
.heroes li:hover {
color: #607D8B;
background-color: #DDD;
left: .1em;
}
.heroes .text {
position: relative;
top: -3px;
}
.heroes .badge {
display: inline-block;
font-size: small;
color: white;
padding: 0.8em 0.7em 0 0.7em;
background-color: #607D8B;
line-height: 1em;
position: relative;
left: -1px;
top: -4px;
height: 1.8em;
margin-right: .8em;
border-radius: 4px 0 0 4px;
}
`]
})
export class AppComponent {
title = 'Tour of Heroes';
heroes = HEROES;
selectedHero: Hero;
onSelect(hero: Hero) { this.selectedHero = hero; }
}
var HEROES: Hero[] = [
{ "id": 11, "name": "Mr. Nice" },
{ "id": 12, "name": "Narco" },
{ "id": 13, "name": "Bombasto" },
{ "id": 14, "name": "Celeritas" },
{ "id": 15, "name": "Magneta" },
{ "id": 16, "name": "RubberMan" },
{ "id": 17, "name": "Dynama" },
{ "id": 18, "name": "Dr IQ" },
{ "id": 19, "name": "Magma" },
{ "id": 20, "name": "Tornado" }
];
浏览器中显示如下:
参考资料
Angular2官方文档