Angular9 显示数据
在视图中显示数据
各种 Angular 组件构成了应用的数据结构。 组件关联到的 HTML 模板提供了在 Web 页面的上下文中显示数据的各种方法。 组件类和模板,共同构成了应用数据的一个视图。
在页面上把数据的值及其表现形式组合起来的过程,就叫做数据绑定。 通过将 HTML 模板中的各个控件绑定到组件类中的各种数据属性,你就把数据展示给了用户(并从该用户收集数据)。
另外,你可以使用指令来向模板中添加逻辑,指令告诉 Angular 在渲染页面时要如何修改。
Angular 定义了一种模板语言,它扩展了 HTML 标记,其扩展语法可以让你定义各种各样的数据绑定和逻辑指令。 当渲染完此页面之后,Angular 会解释这种模板语法,来根据你的逻辑更新 HTML 和数据的当前状态。 在你读完模板语法这章之前,本页中的练习可以先让你快速了解下这种模板语法的工作方式。
在这个示例中,你将创建一个带有英雄列表的组件。 你会显示出这些英雄的名字清单,某些情况下,还会在清单下方显示一条消息。 最终的用户界面是这样的:
使用插值显示组件属性
要显示组件的属性,最简单的方式就是通过插值 (interpolation) 来绑定属性名。 要使用插值,就把属性名包裹在双花括号里放进视图模板,如 {{myHero}}。
使用 CLI
命令 ng new displaying-data
创建一个工作空间和一个名叫 displaying-data
的应用。
删除 "app.component.html" 文件,这个范例中不再需要它了。
然后,到 "app.component.ts" 文件中修改组件的模板和代码。
修改完之后,它应该是这样的:
Path:"src/app/app.component.ts"
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<h1>{{title}}</h1>
<h2>My favorite hero is: {{myHero}}</h2>
`
})
export class AppComponent {
title = 'Tour of Heroes';
myHero = 'Windstorm';
}
再把两个属性 title
和 myHero
添加到之前空白的组件中。
修改完的模板会使用双花括号形式的插值来显示这两个模板属性:
Path:"src/app/app.component.ts (template)"
template: `
<h1>{{title}}</h1>
<h2>My favorite hero is: {{myHero}}</h2>
`
模板是包在 ECMAScript 2015 反引号 (`) 中的一个多行字符串。 允许把一个字符串写在多行上, 使 HTML 模板更容易阅读。
Angular 自动从组件中提取 title
和 myHero
属性的值,并且把这些值插入浏览器中。当这些属性发生变化时,Angular 就会自动刷新显示。
严格来说,“重新显示”是在某些与视图有关的异步事件之后发生的,例如,按键、定时器完成或对 HTTP 请求的响应。
注:
- 你没有调用 new 来创建 AppComponent 类的实例,是 Angular 替你创建了它。那么它是如何创建的呢?
-@Component
装饰器中指定的 CSS 选择器selector
,它指定了一个叫<app-root&
的元素。 该元素是 "index.html" 文件里的一个占位符。
Path:"src/index.html (body)"
<body>
<app-root></app-root>
</body>
当你通过 "main.ts" 中的 AppComponent
类启动时,Angular 在 "index.html" 中查找一个 <app-root>
元素, 然后实例化一个 AppComponent
,并将其渲染到 <app-root>
标签中。
运行应用。它应该显示出标题和英雄名:
选择模板来源
@Component
元数据告诉 Angular 要到哪里去找该组件的模板。 你有两种方式存放组件的模板。
你可以使用 @Component
装饰器的 template
属性来定义内联模板。内联模板对于小型示例或测试很有用。
此外,你还可以把模板定义在单独的 HTML 文件中,并且让 @Component
装饰器的 templateUrl
属性指向该文件。这种配置方式通常用于所有比小型测试或示例更复杂的场景中,它也是生成新组件时的默认值。
无论用哪种风格,模板数据绑定在访问组件属性方面都是完全一样的。 这里的应用使用了内联 HTML,是因为该模板很小,而且示例也很简单,用不到外部 HTML 文件。
- 默认情况下,Angular CLI 命令
ng generate component
在生成组件时会带有模板文件,你可以通过参数来覆盖它:
ng generate component hero -t
初始化
下面的例子使用变量赋值来对组件进行初始化。
export class AppComponent {
title: string;
myHero: string;
constructor() {
this.title = 'Tour of Heroes';
this.myHero = 'Windstorm';
}
}
你可以用构造函数来代替这些属性的声明和初始化语句。
添加循环遍历数据的逻辑
*ngFor
指令(Angular 预置)可以让你循环遍历数据。下面的例子使用该指令来显示数组型属性中的所有值。
要显示一个英雄列表,先向组件中添加一个英雄名字数组,然后把 myHero
重定义为数组中的第一个名字。
Path:"src/app/app.component.ts (class)"
export class AppComponent {
title = 'Tour of Heroes';
heroes = ['Windstorm', 'Bombasto', 'Magneta', 'Tornado'];
myHero = this.heroes[0];
}
接着,在模板中使用 Angular 的 ngFor
指令来显示 heroes 列表中的每一项。
Path:"src/app/app.component.ts (template)"
template: `
<h1>{{title}}</h1>
<h2>My favorite hero is: {{myHero}}</h2>
<p>Heroes:</p>
<ul>
<li *ngFor="let hero of heroes">
{{ hero }}
</li>
</ul>
`
这个界面使用了由 <ul>
和 <li>
标签组成的无序列表。<li>
元素里的 *ngFor
是 Angular 的“迭代”指令。 它将 <li>
元素及其子级标记为“迭代模板”:
Path:"src/app/app.component.ts (li)"
<li *ngFor="let hero of heroes">
{{ hero }}
</li>
注:
- 不要忘记*ngFor
中的前导星号 (*
)。它是语法中不可或缺的一部分。
注意看 ngFor
双引号表达式中的 hero
,它是一个模板输入变量。 更多模板输入变量的信息,见模板语法中的 微语法 (microsyntax
)。
Angular 为列表中的每个条目复制一个 <li>
元素,在每个迭代中,把 hero
变量设置为当前条目(英雄)。 Angular 把 hero
变量作为双花括号插值的上下文。
本例中,
ngFor
用于显示一个“数组”, 但ngFor
可以为任何可迭代的 (iterable
) 对象重复渲染条目。
现在,英雄们出现在了一个无序列表中。
为数据创建一个类
应用代码直接在组件内部直接定义了数据。 作为演示还可以,但它显然不是最佳实践。
现在使用的是到了一个字符串数组的绑定。在真实的应用中,大多是到一个对象数组的绑定。
要将此绑定转换成使用对象,需要把这个英雄名字数组变成 Hero
对象数组。但首先得有一个 Hero
类。
ng generate class hero
此命令创建了如下代码:
Path:"src/app/hero.ts"
export class Hero {
constructor(
public id: number,
public name: string) { }
}
你定义了一个类,具有一个构造函数和两个属性:id
和 name
。
它可能看上去不像是有属性的类,但它确实有,利用的是 TypeScript 提供的简写形式 —— 用构造函数的参数直接定义属性。
来看第一个参数:
Path:"src/app/hero.ts (id)"
public id: number,
这个简写语法做了很多:
- 声明了一个构造函数参数及其类型。
- 声明了一个同名的公共属性。
- 当创建该类的一个实例时,把该属性初始化为相应的参数值。
使用 Hero 类
导入了 Hero 类之后,组件的 heroes 属性就可以返回一个类型化的Hero 对象数组了。
Path:"src/app/app.component.ts (heroes)"
heroes = [
new Hero(1, 'Windstorm'),
new Hero(13, 'Bombasto'),
new Hero(15, 'Magneta'),
new Hero(20, 'Tornado')
];
myHero = this.heroes[0];
接着,修改模板。 现在它显示的是英雄的 id
和 name
。 要修复它,只显示英雄的 name
属性就行了。
Path:"src/app/app.component.ts (template)"
template: `
<h1>{{title}}</h1>
<h2>My favorite hero is: {{myHero.name}}</h2>
<p>Heroes:</p>
<ul>
<li *ngFor="let hero of heroes">
{{ hero.name }}
</li>
</ul>
`
显示上还和以前一样,不过代码更清晰了。
通过 NgIf 进行条件显示
有时,应用需要只在特定情况下显示视图或视图的一部分。
来改一下这个例子,如果多于三位英雄,显示一条消息。
Angular 的 ngIf
指令会根据一个布尔条件来显示或移除一个元素。 来看看实际效果,把下列语句加到模板的底部:
Path:"src/app/app.component.ts (message)"
<p *ngIf="heroes.length > 3">There are many heroes!</p>
双引号内的模板表达式 *ngIf="heroes.length > 3"
的外观和行为与 TypeScript 非常相似。当组件的英雄列表包含三个以上的条目时,Angular 会将这段话添加到 DOM 中,这条消息就显示出来了。如果只有三个或更少的条目,Angular 就会省略该段落,也就不会显示任何消息。
双引号中的模板表达式 *ngIf="heros.length > 3"
,外观和行为很象 TypeScript。 当组件中的英雄列表有三个以上的条目时,Angular 就会把这个段落添加到 DOM 中,于是消息显示了出来。 如果有三个或更少的条目,则 Angular 会省略这些段落,所以不显示消息。
注:
- Angular 并不是在显示和隐藏这条消息,它是在从 DOM 中添加和移除这个段落元素。 这会提高性能,特别是在一些大的项目中有条件地包含或排除一大堆带着很多数据绑定的 HTML 时。
试一下。因为这个数组中有四个条目,所以消息应该显示出来。 回到 "app.component.ts",从英雄数组中删除或注释掉一个元素。 浏览器应该自动刷新,消息应该会消失。
源代码
- Path:"src/app/app.component.ts"
import { Component } from '@angular/core';
import { Hero } from './hero';
@Component({
selector: 'app-root',
template: `
<h1>{{title}}</h1>
<h2>My favorite hero is: {{myHero.name}}</h2>
<p>Heroes:</p>
<ul>
<li *ngFor="let hero of heroes">
{{ hero.name }}
</li>
</ul>
<p *ngIf="heroes.length > 3">There are many heroes!</p>
`
})
export class AppComponent {
title = 'Tour of Heroes';
heroes = [
new Hero(1, 'Windstorm'),
new Hero(13, 'Bombasto'),
new Hero(15, 'Magneta'),
new Hero(20, 'Tornado')
];
myHero = this.heroes[0];
}
- Path:"src/app/hero.ts"
export class Hero {
constructor(
public id: number,
public name: string) { }
}
- Path:"src/app/app.module.ts"
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
@NgModule({
imports: [
BrowserModule
],
declarations: [
AppComponent
],
bootstrap: [ AppComponent ]
})
export class AppModule { }
- Path:"main.ts"
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule);
总结
现在您知道了如何使用:
- 带有双花括号的插值 (
interpolation
) 来显示一个组件属性。
- 用
ngFor
显示数组。
- 用一个 TypeScript 类来为你的组件描述模型数据并显示模型的属性。
- 用
ngIf
根据一个布尔表达式有条件地显示一段 HTML。
更多建议: