[Angular2] Case Study:Tour of Heroes - 对象、列表

在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

显示Hero信息

AppComponent添加两个属性:

export class AppComponent {
  public title = 'Tour of Heroes';
  public hero = 'Windstorm';
}

更新模板:

template: '<h1>{{title}}</h1><h2>{{hero}} details!</h2>'

浏览器会自动刷新,显示结果如下:

Hero对象

上面的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:多行字符串可以使用反引号。

浏览器中显示如下:

[Angular2] Case Study:Tour of Heroes - 对象、列表_第1张图片

编辑Hero

添加一个文本框用于编辑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">

浏览器中显示如下:

[Angular2] Case Study:Tour of Heroes - 对象、列表_第2张图片

至此,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'
  };
}

显示Hero列表(数组)

在文件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" }
];

浏览器中显示如下:

选择Hero

目前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,这时selectedHeroundefined。将详细信息放入<div>中,并使用ngIf指令,这样当selectedHeroundefined时就不显示该<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] Case Study:Tour of Heroes - 对象、列表_第3张图片

参考资料

Angular2官方文档

你可能感兴趣的:([Angular2] Case Study:Tour of Heroes - 对象、列表)