Angular 显示英雄列表

在本页面,你将扩展《英雄指南》应用,让它显示一个英雄列表, 并允许用户选择一个英雄,查看该英雄的详细信息。

创建模拟(mock)英雄数据

你需要一些英雄数据以供显示。

最终,你会从远端的数据服务器获取它。但是目前,你需要创建一些模拟英雄(some mock heroes),并假设这些数据是从远程服务器上获取的。

在src/app/文件夹中创建一个名叫mock-heroes.ts的文件。 定义一个包含十个英雄的常量数组HEROES,并导出它。 该文件是这样的。

src/app/mock-heroes.ts

import{ Hero } from './hero';


export constHEROES: 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'}

];

显示英雄

你要在HeroesComponent的顶部显示这个英雄列表。

打开HeroesComponent类文件,并导入模拟的HEROES 数据。

src/app/heroes/heroes.component.ts

import{ HEROES } from '../mock-heroes';

往类中添加一个heroes属性,这样可以暴露出这些英雄,以供绑定。

src/app/heroes/heroes.component.ts

export classHeroesComponent implementsOnInit {


  heroes = HEROES;

使用*ngFor列出这些英雄

打开HeroesComponent的模板文件,并做如下修改:

在顶部添加

然后添加表示无序列表的 HTML 元素(

      中插入一个
    • 元素,以显示单个hero的属性。

      点缀上一些 CSS 类(稍后你还会添加更多 CSS 样式)。

      完成后应该如下显示:

      heroes.component.html

      heroes.component.html (heroes template)

      content_copy

      My Heroes

        

    •     {{hero.id}} {{hero.name}}

        

    现在,把

  • 修改成这样:

  • *ngFor是一个 Angular 的复写器(repeater)指令。 它会为列表中的每项数据复写它的宿主元素。

    在这个例子中

  • 就是*ngFor的宿主元素

    heroes就是来自HeroesComponent类的列表。

    当依次遍历这个列表时,hero会为每个迭代保存当前的英雄对象。

    不要忘了ngFor前面的星号(*),它是该语法中的关键部分。

    浏览器刷新之后,英雄列表出现了。

    给英雄们应用样式表

    英雄列表应该富有吸引力,并且当用户把鼠标移到某个英雄上和从列表中选中某个英雄时,应该给出视觉反馈。

    在教程的第一章,你曾在styles.css中为整个应用设置了一些基础的样式。 但那个样式表并不包含英雄列表所需的样式。

    固然,你可以把更多样式加入到styles.css,并且放任它随着你添加更多组件而不断膨胀。

    但还有更好的方式。你可以定义属于特定组件的私有样式,并且让组件所需的一切(代码、HTML 和 CSS)都放在一起。

    这种方式让你在其它地方复用该组件更加容易,并且即使全局样式和这里不一样,组件也仍然具有期望的外观。

    你可以用多种方式定义私有样式,或者内联在@Component.styles数组中,或者在@Component.styleUrls所指出的样式表文件中。

    当 CLI 生成HeroesComponent时,它也同时为HeroesComponent创建了空白的heroes.component.css样式表文件,并且让@Component.styleUrls指向它,就像这样:

    src/app/heroes/heroes.component.ts

    @Component({

      selector: 'app-heroes',

      templateUrl: './heroes.component.html',

      styleUrls: ['./heroes.component.css']

    })

    打开heroes.component.css文件,并且把HeroesComponent的私有 CSS 样式粘贴进去。 你可以在本指南底部的查看最终代码中找到它们。

    @Component元数据中指定的样式和样式表都是局限于该组件的。heroes.component.css中的样式只会作用于HeroesComponent,既不会影响到组件外的 HTML,也不会影响到其它组件中的 HTML。

    主从结构

    当用户在列表中点击一个英雄时,该组件应该在页面底部显示所选英雄的详情

    在本节,你将监听英雄条目的点击事件,并更新英雄的详情。

    添加click事件绑定

    再往

  • 元素上插入一句点击事件的绑定代码:

    heroes.component.html

  • 这是 Angular事件绑定语法的例子。

    click外面的圆括号会让 Angular 监听这个

  • 元素的click事件。 当用户点击
  • 时,Angular 就会执行表达式onSelect(hero)。

    onSelect()是HeroesComponent上的一个方法,你很快就要写它。 Angular 会把所点击的

  • 上的hero对象传给它,这个hero也就是前面在*ngFor表达式中定义的那个。

    添加click事件处理器

    把该组件的hero属性改名为selectedHero,但不要为它赋值。 因为应用刚刚启动时并没有所选英雄

    添加如下onSelect()方法,它会把模板中被点击的英雄赋值给组件的selectedHero属性。

    src/app/heroes/heroes.component.ts

    selectedHero: Hero;

    onSelect(hero: Hero): void{

      this.selectedHero = hero;

    }

    修改详情模板

    该模板引用的仍然是老的hero属性,但它已经不存在了。 把hero改名为selectedHero。

    heroes.component.html

    {{selectedHero.name | uppercase}} Details

    id: {{selectedHero.id}}

      

        

      

    刷新浏览器,应用挂了。

    打开浏览器的开发者工具,它的控制台中显示出如下错误信息:

    HeroesComponent.html:3ERROR TypeError: Cannot read property 'name'of undefined

    出现了什么问题?

    当应用启动时,selectedHero是undefined,设计如此

    但模板中的绑定表达式引用了selectedHero的属性(表达式为{{selectedHero.name}}),这必然会失败,因为你还没选过英雄呢。

    现在,从列表中随便点击一个条目。 应用又正常了。 英雄们显示在列表中,并且所点英雄的详情也显示在了页面的下方。

    修复 - 使用*ngIf 来隐藏空白的细节

    该组件应该只有当selectedHero存在时才显示所选英雄的详情。

    把显示英雄详情的 HTML 包裹在一个

    中。 并且为这个 div 添加 Angular 的*ngIf指令,把它的值设置为selectedHero。

    不要忘了ngIf前面的星号(*),它是该语法中的关键部分。

    src/app/heroes/heroes.component.html (*ngIf)


      

    {{selectedHero.name | uppercase}} Details

      

    id: {{selectedHero.id}}

      

        

          

        

      


    浏览器刷新之后,英雄名字的列表又出现了。 详情部分仍然是空。 点击一个英雄,它的详情就出现了。 这个应用看起来又再次工作正常显示了。 英雄显示在列表中,当你单击英雄的名字的时候,有关你单击英雄的详细信息就显示在页面的底部了。

    为什么这样是正常的

    当selectedHero为undefined时,ngIf从 DOM 中移除了英雄详情。因此也就不用担心selectedHero的绑定了。

    当用户选择一个英雄时,selectedHero也就有了值,并且ngIf把英雄的详情放回到 DOM 中。

    给所选英雄添加样式

    所有的

  • 元素看起来都是一样的,因此很难从列表中识别出所选英雄

    如果用户点击了“Magneta”,这个英雄应该用一个略有不同的背景色显示出来,就像这样:

    所选英雄的颜色来自于你前面添加的样式中的 CSS 类.selected。 所以你只要在用户点击一个

  • 时把.selected类应用到该元素上就可以了。

    Angular 的CSS 类绑定机制让根据条件添加或移除一个 CSS 类变得很容易。 只要把[class.some-css-class]="some-condition"添加到你要施加样式的元素上就可以了。

    在HeroesComponent模板中的

  • 元素上添加[class.selected]绑定,代码如下:

    heroes.component.html (toggle the 'selected' CSS class)

    [class.selected]="hero === selectedHero"

    如果当前行的英雄和selectedHero相同,Angular 就会添加 CSS 类selected,否则就会移除它。

    最终的

  • 是这样的:

    heroes.component.html (list item hero)

  •   [class.selected]="hero === selectedHero"

      (click)="onSelect(hero)">

      {{hero.id}} {{hero.name}}

  • 查看最终代码

    你的应用现在变成了这样:在线例子/下载范例。

    下面是本页面中所提及的代码文件,包括HeroesComponent的样式。

    对应的文件列表和代码链接如下:

    文件名源代码

    src/app/heroes/heroes.component.tshttps://github.com/cwiki-us-angular/cwiki-us-angular-tour-of-heroes-list/blob/master/src/app/heroes/heroes.component.ts

    src/app/heroes/heroes.component.htmlhttps://github.com/cwiki-us-angular/cwiki-us-angular-tour-of-heroes-list/blob/master/src/app/heroes/heroes.component.html

    src/app/heroes/heroes.component.csshttps://github.com/cwiki-us-angular/cwiki-us-angular-tour-of-heroes-list/blob/master/src/app/heroes/heroes.component.css

    小结

    英雄指南应用在一个主从视图中显示了英雄列表。

    用户可以选择一个英雄,并查看该英雄的详情。

    你使用*ngFor显示了一个列表。

    你使用*ngIf来根据条件包含或排除了一段 HTML。

    你可以用class绑定来切换 CSS 的样式类。

    https://www.cwiki.us/display/AngularZH/Display+a+Heroes+List

你可能感兴趣的:(Angular 显示英雄列表)