版本:Angular 5.0.0-alpha
在 Angular 中最典型的数据显示方式,就是把 HTML 模板中的控件绑定到 Angular 组件的属性。
本章,你将创建一个英雄列表组件。显示英雄名字的列表,并根据条件在列表下方显示一条消息。
最终的用户界面是这样的:
在线示例(查看源码)演示了本章描述的所有语法和代码片段。
使用插值表达式显示组件属性
要显示组件的属性,最简单的方式就是通过插值表达式 (interpolation) 来绑定属性名。 要使用插值表达式,就把属性名包裹在双花括号里放进视图模板,如{{myHero}}
。
按照配置开发环境的说明,创建一个名为displaying_data
的新项目。
然后,到app_component.dart
文件,修改组件的模板和代码。
修改完之后,应该是这样的:
// lib/app_component.dart
import 'package:angular/angular.dart';
@Component(
selector: 'my-app',
template: '''
{{title}}
My favorite hero is: {{myHero}}
''',
)
class AppComponent {
final title = 'Tour of Heroes';
String myHero = 'Windstorm';
}
再把两个属性title
和myHero
添加到之前空白的组件中。
修改完的模板会使用双花括号形式的插值表达式来显示这两个模板属性:
template: '''
{{title}}
My favorite hero is: {{myHero}}
''',
Angular 自动从组件中提取title
和myHero
属性的值,并且把这些值插入浏览器中。当这些属性发生变化时,Angular 就会自动更新显示。
严格来说,“重新显示”是在某些与视图有关的异步事件之后发生的,例如,按键、定时器完成或对 HTTP 请求的响应。
注意,我们没有调用 new
来创建AppComponent
类的实例,是 Angular 替我们创建了它。那么它是如何创建的呢?
在@Component
注解中的 CSS 选择器 selector
,指定一个名为
的元素。该元素是index.html
的 body
里的占位符。
// web/index.html(body)
Loading...
当你通过AppComponent
类(在web/main.ts
中)启动应用时,Angular 在index.html
中查找一个
元素,找到它,然后实例化一个AppComponent
的实例,并将其渲染到
标签中。
现在运行应用。它应该显示出标题和英雄名:
内联 (inline) 模板还是模板文件?
我们可以在两种地方存放组件模板。使用template
属性把它定义为内联的,或者把模板定义在一个独立的 HTML 文件中,再通过@Component
注解中的templateUrl
属性,把它链接到组件元数据。
到底选择内联 HTML 还是独立 HTML 取决于个人喜好、具体状况和组织策略。上面的应用选择内联 HTML,是因为模板很小,而且没有额外的 HTML 文件显得这个演示简单些。
无论用哪种风格,模板数据绑定在访问组件属性方面都是完全一样的。
使用 *ngFor显示一列属性
要显示一列英雄,先向组件中添加一个包含英雄名字的列表,然后把myHero
重新定义为列表中的第一个名字。
// lib/app_component.dart (class)
class AppComponent {
final title = 'Tour of Heroes';
List heroes = [
'Windstorm',
'Bombasto',
'Magneta',
'Tornado',
];
String get myHero => heroes.first;
}
现在,在模板中使用 Angular 的ngFor
指令来显示heroes
列表中的每一项。
template: '''
{{title}}
My favorite hero is: {{myHero}}
Heroes:
-
{{ hero }}
''',
directives: const [CORE_DIRECTIVES] // 使用ngFor 一定要声明指令
这个界面使用了由
和 标签组成的无序列表。
元素里的
*ngFor
是 Angular 的“重复”指令。它将元素(及其子元素)标记为“重复模板”:
{{ hero }}
不要忘记
*ngFor
中的前导星号 (*)。它是语法中不可或缺的一部分。更多信息,见模板语法。
注意看ngFor
双引号表达式中的hero
,它是一个模板输入变量。 更多模板输入变量的信息,见模板语法中的微语法。
Angular 为列表中的每个条目复制一个元素,在每个迭代中,把
hero
变量设置为当前条目(英雄)。Angular 把hero
变量作为双花括号插值表达式的上下文。
本例中,
ngFor
用于显示一个列表,但ngFor
可以为任意
Iterable 对象重复条目。
@Component(directives: …)
在模板中使用任何 Angular 指令之前,需要在组件的
@Component
注解的directives
列表中声明它们。可以单独的列出指令,或者为了方便起见使用 CORE_DIRECTIVES:
// lib/app_component.dart (directives)
import 'package:angular/angular.dart';
@Component(
selector: 'my-app',
// ···
directives: [coreDirectives],
)
刷新浏览器。现在,英雄们出现在了一个无序列表中。
为数据创建一个类
应用代码直接在组件内部直接定义了数据。作为演示还可以,但它显然不是最佳实践。
现在使用的是到一个字符串列表的绑定。在真实的应用中,大多数是绑定到一个专门的对象。
要将此绑定转换成使用专门的对象,需要把这个英雄名字的列表变成Hero
对象的列表。因此,你需要一个Hero
类。
在lib
目录创建一个名为hero.dart
的新文件,内容如下:
// lib/src/hero.dart
class Hero {
final int id;
String name;
Hero(this.id, this.name);
@override
String toString() => '$id: $name';
}
你定义了一个包含一个构造函数,两个属性(id
和name
)和一个toString()
方法的类。
使用 Hero 类
导入了Hero
类之后,AppComponent.heroes
属性就可以返回一个Hero
对象类型的列表了。
// lib/app_component.dart
List heroes = [
new Hero(1, 'Windstorm'),
new Hero(13, 'Bombasto'),
new Hero(15, 'Magneta'),
new Hero(20, 'Tornado')
];
Hero get myHero => heroes.first;
接下来,修改模板。现在它显示的是英雄的id
和name
。修复它,只显示英雄的name
属性。
// lib/app_component.dart (template)
template: '''
{{title}}
My favorite hero is: {{myHero.name}}
Heroes:
-
{{ hero.name }}
''',
显示上还和以前一样,不过代码更清晰了。
通过 NgIf 进行条件显示
有时,应用需要只在特定情况下显示视图或视图的一部分。
让我们来修改这个例子,如果多于三位英雄,显示一条消息。
Angular 的ngIf
指令会根据一个布尔条件,插入或移除元素。通过把下面的段落添加到模板的底部,我们可以看到实际效果。
// lib/app_component.dart (message)
3">There are many heroes!
不要忘了
*ngIf
中的前导星号 (*
)。它是本语法中不可或缺的一部分。 更多ngIf
和*
的内容,见模板语法的 ngIf 部分。
双引号中的模板表达式,*ngIf ="heros.length > 3"
,看起来就像是 Dart。当组件中的英雄列表有三个以上时,Angular 把这个段落添加到 DOM 中,于是消息显示了出来。如果有3个或少于3个,Angular 会忽略这个段落,所以就没有信息显示。更多信息,见模板语法中的模板表达式部分。
Angular 并不是在显示和隐藏这条消息,它是在从 DOM 中添加和移除这个段落元素。这会提高性能,特别是在一些大的项目中有条件地包含或排除一大堆带着很多数据绑定的 HTML 时。
试一下。因为列表中有四个条目,所以消息显示了出来。回到app_component.dart
,从英雄列表中删除或注释掉一个元素。浏览器刷新后,信息应该不存在了。
总结
现在你学会了如何使用:
- 带有双花括号的插值表达式来显示一个组件属性。
- ngFor 来显示一列条目。
- 用一个 Dart 类来为组件描述模型数据并显示模型的属性。
- ngIf 来根据一个布尔表达式有条件的显示一段HTML。
下一步
用户输入