文档章节

AngularDart4.0 英雄之旅-教程-04明细

scooplol
 scooplol
发布于 2017/10/24 09:12
字数 2678
阅读 68
收藏 0

在此页面中,您将扩展“Tour of Heroes”应用程序,以显示英雄列表,并允许用户选择英雄并显示英雄的详细信息。

完成此页面后,该应用应该看起来像这个实例(查看源代码)。

必备条件

在继续本“英雄之旅”页面之前,请确认您在“英雄编辑器”页面之后具有以下结构。 如果您的结构不匹配,请返回该页面以弄清楚您错过了什么。

如果该应用尚未运行,请启动该应用。 当您进行更改时,请通过重新加载浏览器窗口来保持运行

应用程序重构

在添加新功能之前,您可以从应用程序重构中受益。

应用模板文件

您将对应用程序组件的模板进行多次更新。 首先,将模板移动到自己的文件中:

lib/app_component.html

<h1>{{title}}</h1>
<h2>{{hero.name}} details!</h2>
<div><label>id: </label>{{hero.id}}</div>
<div>
  <label>name: </label>
  <input [(ngModel)]="hero.name" placeholder="name">
</div>

用指向新模板文件的templateUrl替换@Component模板:

lib/app_component.dart (metadata)

@Component(
  selector: 'my-app',
  templateUrl: 'app_component.html',
  directives: const [formDirectives],
)

刷新浏览器。 该应用仍然继续运行。

Hero类

 分开使用并将Hero类从app_component.dart 中移动到它自己的文件中,创建lib/src文件夹来装Hero源文件:lib/src/hero.dart

class Hero {
  final int id;
  String name;

  Hero(this.id, this.name);
}

回到应用程序组件中,使用相对路径添加一个import 到新创建的文件:lib/app_component.dart (hero import)

import 'src/hero.dart';

刷新浏览器,程序将正常运行,现在添加新功能的准备工作就做好了。

展示英雄们

    显示一个英雄列表,首先需要将英雄们添加到视图模板

模拟英雄

    在lib / src下的以下文件中创建十个英雄的列表:lib/src/mock_heroes.dart

import 'hero.dart';

final mockHeroes = <Hero>[
  new Hero(11, 'Mr. Nice'),
  new Hero(12, 'Narco'),
  new Hero(13, 'Bombasto'),
  new Hero(14, 'Celeritas'),
  new Hero(15, 'Magneta'),
  new Hero(16, 'RubberMan'),
  new Hero(17, 'Dynama'),
  new Hero(18, 'Dr IQ'),
  new Hero(19, 'Magma'),
  new Hero(20, 'Tornado')
];

最终这个应用程序将从Web服务获取英雄列表,但现在你可以显示模拟英雄。

应用hero字段

hero字段替换为AppComponent中的公共heros字段,并使用模拟英雄进行初始化(不要忘记导入):lib/app_component.dart (heroes)

import 'src/mock_heroes.dart';

// ···
class AppComponent {
  final title = 'Tour of Heroes';
  List<Hero> heroes = mockHeroes;
  // ···
}

英雄数据与类实现分开,因为英雄名字最终将来自数据服务。

 在模板中显示英雄名称

 要在无序列表中显示英雄名称,请将所有当前模板替换为以下HTML:lib/app_component.html (heroes template)

<h1>{{title}}</h1>
<h2>My Heroes</h2>
<ul class="heroes">
  <li>
    <!-- each hero goes here -->
  </li>
</ul>

下一步你将添加英雄名字

使用ngFor指令罗列英雄

目标是将组件中的英雄列表绑定到模板,迭代它们,并单独显示它们。通过添加核心指令* ngFor修改<li>标签。

<li *ngFor="let hero of heroes">

 ngFor的前缀(*)是此语法的关键部分。 它表示<li>元素及其子元素构成一个主模板。

 ngFor指令遍历组件的英雄列表并为该列表中的每个英雄呈现该模板的一个实例。

表达式部分将hero标识为模板输入变量,其中包含每个迭代的英雄详情。

你可以在模板中引用这个变量来访问当前英雄的属性。

显示数据Showing a list property with *ngFor部分阅读更多关于ngFor和模板输入变量和模板语法页ngFor部分

<li>节点内添加内容hero模板变量来显示英雄属性 lib/app_component.html (ngFor)

<li *ngFor="let hero of heroes">
  <span class="badge">{{hero.id}}</span> {{hero.name}}
</li>

要在模板中使用Angular指令,需要在组件的@Component注解的指令参数中列出。 与您在第1部分中所做的相似,添加所有:CORE_DIRECTIVES

CORE_DIRECTIVES = const [NgClass, NgFor, NgIf, NgTemplateOutlet, NgStyle, NgSwitch, NgSwitchWhen, NgSwitchDefault]

lib/app_component.dart (directives)

@Component(
  selector: 'my-app',
  // ···
  directives: const [CORE_DIRECTIVES, formDirectives],
)

刷新浏览器,英雄列表将显示出来。

装饰英雄

用户应该得到一个他们徘徊和被选中英雄的视觉提示。要为组件添加样式,可以设置@Component注解的styles参数:lib/app_component.dart (styles)

// Not recommended when adding many CSS classes:
styles: const [
  '''
    .selected { ... }
    .heroes { ... }
    ...
  '''
],

但是,当添加多个样式时,这使得Dart文件更长,更不易读。 而应将样式放在.css文件中,并使用@ComponentstyleUrls参数引用该文件。 按照惯例,组件的CSS和Dart文件的名称具有相同的基础命名前缀(app_component)。lib/app_component.dart (stylUrls)

@Component(
  selector: 'my-app',
  // ···
  styleUrls: const ['app_component.css'],
  // ···
)

lib/app_component.css 

.selected {
  background-color: #CFD8DC !important;
  color: white;
}
.heroes {
  margin: 0 0 2em 0;
  list-style-type: none;
  padding: 0;
  width: 15em;
}
.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 {
  color: white;
}
.heroes li:hover {
  color: #607D8B;
  background-color: #EEE;
  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;
}

将样式分配给组件时,它们的作用域为该特定组件。 这些样式仅适用于AppComponent,不影响外部HTML。

显示英雄的模板应该是这样的:lib/app_component.html (styled heroes)

<h2>My Heroes</h2>
<ul class="heroes">
  <li *ngFor="let hero of heroes">
    <span class="badge">{{hero.id}}</span> {{hero.name}}
  </li>
</ul>

选择一个英雄

该应用程序现在显示英雄列表,以及在详细信息视图中的单个英雄。 但是列表和细节视图没有连接。 当用户从列表中选择一个英雄时,选择的英雄应该出现在细节视图中。 这个UI模式被称为“主/细节”。在这种情况下,主人是英雄列表,细节是选择的英雄。

接下来,您将通过selectedHero组件属性将主链接到详细信息,该属性绑定到单击事件。

处理点击事件

添加点击事件绑定到<li>lib/app_component.html (click)

<li *ngFor="let hero of heroes" (click)="onSelect(hero)">
  <span class="badge">{{hero.id}}</span> {{hero.name}}
</li>

圆括号将<li>元素的点击事件标识为目标。 onSelect(hero)表达式调用AppComponent方法onSelect(),传递模板输入变量hero作为参数。 这是你在ngFor指令中定义的同一个英雄变量。

用户输入页面和模板语法页面的事件绑定部分了解有关事件绑定的更多信息。

添加一个点击处理程序来显示选定的英雄 

你不再需要hero属性,因为你不再显示一个英雄; 你正在显示一个英雄列表。 但是用户可以通过点击选择一个英雄。 所以用这个简单的selectedHero属性来替换hero属性:lib/app_component.dart (selectedHero)

Hero selectedHero;

在用户选择英雄之前,所有的英雄名字都应该被取消选择,所以你不会像hero一样初始化selectedHero。添加一个onSelect()方法,将selectedHero属性设置为用户单击的英雄。lib/app_component.dart (onSelect)

void onSelect(Hero hero) => selectedHero = hero;

该模板仍然是指旧的英雄属性。 绑定到新的selectedHero属性,如下所示:lib/app_component.html (selectedHero details)

<h2>{{selectedHero.name}} details!</h2>
<div><label>id: </label>{{selectedHero.id}}</div>
<div>
  <label>name: </label>
  <input [(ngModel)]="selectedHero.name" placeholder="name">
</div>

使用ngIf指令隐藏空的对象

当应用程序加载时,selectedHeronull。 当用户点击英雄的名字时,所选择的英雄被初始化。 Angular无法显示null selectedHero的属性并抛出以下错误,在浏览器的控制台中可见:

EXCEPTION: TypeError: Cannot read property 'name' of undefined in [null]

 

尽管selectedHero.name显示在模板中,但必须保留DOM外的英雄详细信息,直到出现选定的英雄。用<div>包装模板的HTML英雄细节内容。 然后添加ngIf核心指令并将其设置为selectedHero!= nulllib/app_component.html (ngIf)

<div *ngIf="selectedHero != null">
  <h2>{{selectedHero.name}} details!</h2>
  <div><label>id: </label>{{selectedHero.id}}</div>
  <div>
    <label>name: </label>
    <input [(ngModel)]="selectedHero.name" placeholder="name">
  </div>
</div>

不要忘记ngIf前面的星号(*)。

刷新浏览器,该应用程序不再失败,名称列表再次显示在浏览器中。

当没有选定的英雄时,ngIf指令从DOM中移除英雄详情HTML。 没有英雄细节元素或绑定担心。

当用户选择一个英雄时,selectedHero变为非nullngIf将英雄详细内容放入DOM中,并评估嵌套的绑定。

结构指令页面和模板语法页面的内置指令部分阅读有关ngIfngFor的更多信息。

格式化选中hero

当选择的英雄细节显示在列表下方时,很难在列表中识别选定的英雄。

在上面添加的样式元数据中,有一个名为selected的自定义CSS类。 为了让选定的英雄更清晰可见,当用户点击英雄名字时,你将把这个选定的class应用到<li>。 例如,当用户点击“Magneta”时,它应该用一个独特但微妙的背景颜色渲染,如下所示:

在模板中,将以下绑定添加到<li>标记中:

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

当表达式(hero === selectedHero)为true时,Angular将添加所选的CSS类。 当表达式为false时,Angular删除选定的类。

===运算符测试给定的对象是否相同

模板语法指南中阅读有关[class]绑定的更多信息。

 <li>的最终版本如下所示:lib/app_component.html (ngFor with class.selected)

<li *ngFor="let hero of heroes"
    [class.selected]="hero === selectedHero"
    (click)="onSelect(hero)">
  <span class="badge">{{hero.id}}</span> {{hero.name}}
</li>

点击“Magneta”后,列表应该如下所示:

回顾应用程序结构

您的项目应该有以下文件:

教程组件测试
本教程不包括测试,但是如果您查看示例代码,则会为本教程添加的每个新功能进行组件测试。 详细信息请参阅组件测试页面。

 

你走过的路

以下是您在此页面中所取得的成果:

英雄之旅(Tour of Heroes)应用程序显示可选英雄列表。
您将应用程序模板移到了自己的文件中。
您将Hero类移到lib / src下的自己的文件中。
你增加了选择英雄和显示英雄的细节的能力。
您了解了如何在组件模板中使用核心指令ngIf和ngFor。
您在CSS文件中定义了样式,并使用它们来设置应用程序的样式。
你的应用应该看起来像这个实例(查看源代码)。

前方的路

你已经扩大了英雄之旅的应用程序,但它还远远没有完成。 一个应用程序不应该是一个单一的组件。 在下一页中,您将将应用程序拆分为子组件,并使它们一起工作。

下一节

© 著作权归作者所有

scooplol
粉丝 17
博文 103
码字总数 205785
作品 0
南充
程序员
私信 提问
AngularDart4.0 英雄之旅-教程-05多组件

AppComponent正在做所有的事情。 一开始,它展示了一个英雄的细节。 然后,它成为一个英雄和英雄细节列表的主/细节形式。 很快就会有新的要求和能力。 您不能在一个组件之上填充所有功能; 这...

scooplol
2017/11/08
62
0
AngularDart4.0 英雄之旅-教程-03英雄编辑器

码云项目页:https://gitee.com/scooplolwiki/toh-1 在这一部分,您将修改起始应用程序以显示有关英雄的信息。 然后,您将添加编辑英雄信息的功能。 完成后,应用程序应该看起来像这个实例(...

scooplol
2017/10/22
84
0
AngularDart4.0 英雄之旅-教程-02启动应用

码云项目页:https://gitee.com/scooplolwiki/toh-0 此教程讲解Angular的文件架构,(查看源代码)查看应用程序。 创建应用 开始,创建名为angulartourof_heroes的项目,使用WebStorm或者命令...

scooplol
2017/10/19
164
11
用Python开发一款王者荣耀的“脚本”!上王者轻轻松!

王者荣耀 -很火的手游-简直老少通吃-令人发指-虽然操作简单-但为什么你还是会被虐, 其实 是有技巧的--本文Python大神带你研究王者荣耀各类英雄的出装小技巧,让你成为大神般的存在 前期准备...

qq_42156420
2018/05/29
0
0
闫伟 2016-09-29 工作日报

分析友谊商店売上明细和前期/当前库存中売上数量不一致的问题,全部是2015-04数据不一致。 分析Pos流水明细和Pos前期/当前库存中销售数量不一致的问题,有些是innerno=3的没有加入统计。...

yanweifree
2016/09/30
1
0

没有更多内容

加载失败,请刷新页面

加载更多

JDBC 连接数据库的流程?

加载 JDBC 驱动程序 利用 url,user,password 创建数据库连接 创建 statement 对象执行 sql 语句 返回查询结果 resultset 关闭连接,释放 JDBC 资源。关闭的顺序与开启的顺序相反:resultset...

happywe
26分钟前
2
0
如何让视频加速播放

当下的视频工作者越来越多,很多人在闲暇时间也会制作一些好玩有趣的短视频上传一些社交媒体。下面分享一个让视频加速播放的软件以及制作方法,学会这个方法后,可以制作一些有趣的加速视频啦...

白米稀饭2019
34分钟前
2
0
生成带图片的二维码

1,pom.xml 中 <!-- ZXing --><dependency> <groupId>com.google.zxing</groupId> <artifactId>core</artifactId> <version>3.3.3</version></dependency><dependency......

简小姐
42分钟前
3
0
可能是国内第一篇全面解读 Java 现状及趋势的文章

作者 | 张晓楠 Dragonwell JDK 最新版本 8.1.1-GA 发布,包括全新特性和更新! **导读:**InfoQ 发布《2019 中国 Java 发展趋势报告》,反映 Java 在中国发展的独特性,同时也希望大家对 Ja...

阿里巴巴云原生
57分钟前
3
0
Mybatis 配置详解

完整配置 mybatis-config.xml <?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.......

xiaolyuh
58分钟前
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部