Angular13 Angular 快速上手

2024-02-25 开发教程 Angular13 匿名 3

Angular 入门

Angular 欢迎你!

本教程将通过构建一个电子商务网站,向你介绍 Angular 的基本知识。该网站具有商品名录、购物车和结账表单。

为了帮助你更好地起步,本教程提供了一个已完成的应用,你可以在 Stackblitz 上试验及互动,而不用建立本地开发环境。 StackBlitz 是一个基于浏览器的开发环境,你可以在其中使用各种技术来创建、保存和共享项目。

先决条件

为了充分利用本教程,你应该已经对以下内容有基本的了解。

浏览范例应用

你可以用组件构建 Angular 应用。组件定义了 UI 中的职责范围,让你可以复用某些 UI 功能集。

一个组件由三部分组成:

  • 处理数据和功能的组件类。
  • 决定 UI 的 HTML 模板。
  • 定义外观的组件专属样式。

本指南演示了如何使用下列组件构建应用。

  • <app-root>​ - 第一个加载的组件,并且是其他组件的容器。
  • <app-top-bar>​ - 商店名称和结帐按钮。
  • <app-product-list>​ - 产品列表。
  • <app-product-alerts>​ - 包含应用中各种通知的组件。

创建范例项目

要创建范例项目,请在 StackBlitz 中生成一个预置的范例项目。要保存你的工作,请执行以下操作:

  1. 登录到 StackBlitz。
  2. 对你生成的项目进行分支。
  3. 定时保存。

在 StackBlitz 中,右侧的预览窗格会显示范例应用的启动状态。此预览有两个区域:

  • 带有商店名称(My Store)和 Checkout 按钮的顶部栏
  • 产品列表及其标题

左侧的项目区显示了构成本应用的源文件,包括基础结构和配置文件。

当你生成本教程随附的 StackBlitz 范例应用时,StackBlitz 会为你创建启动程序文件和模拟数据。本教程中用到的文件位于 ​src ​文件夹中。

有关如何使用 StackBlitz 的更多信息,请参见 StackBlitz 的文档

创建产品列表

在本节中,你将修改应用以显示产品列表。你会用到来自 ​products.ts​ 文件的预定义产品数据,和一些来自 ​product-list.component.ts​ 文件的方法。本节将指导你完成编辑 HTML(也称为模板)的过程。

  1. 在 ​product-list​ 文件夹中,打开模板文件 ​product-list.component.html​。
  2. 在 ​<div>​ 上添加一个结构型指令 ​*ngFor​,如下所示。
<h2>Products</h2>
<div *ngFor="let product of products">
</div>

使用 ​*ngFor​,会把这个 ​<div>​ 针对列表中的每个产品进行复写。

结构型指令会通过添加、删除和操作元素来调整或重塑 DOM 结构。

在此 ​<div>​ 中,添加 ​<h3>​ 和 ​{{ product.name }}​。​{{ product.name }}​ 语句是 Angular 插值语法的范例。插值 ​{{ }}​ 可以让你把属性值渲染为文本。
<h2>Products</h2>
<div *ngFor="let product of products">
<h3>
{{ product.name }}
</h3>
</div>

预览窗格将会更新,以显示列表中每个商品的名称。

为了让每个商品名称都能链接到商品详情,请围绕 ​{{ product.name }}​ 添加一个 ​<a>​ 元素。 使用 ​[ ]​ 语法将标题设置为此产品的名称,如下所示:
<h2>Products</h2>
<div *ngFor="let product of products">
<h3>
<a [title]="product.name + ' details'">
{{ product.name }}
</a>
</h3>
</div>

在预览窗格中,将鼠标悬停在产品名称上,可以查看所绑定的 name 属性值,该值是产品名加上单词 “details”。通过属性绑定 ​[ ]​ 可以在模板表达式中使用属性值。

添加产品说明。在 ​<p>​ 元素上使用 ​*ngIf​ 指令,以便 Angular 只让当前产品有描述 ​<p>
<h2>Products</h2>
<div *ngFor="let product of products">
<h3>
<a [title]="product.name + ' details'">
{{ product.name }}
</a>
</h3>
<p *ngIf="product.description">
Description: {{ product.description }}
</p>
</div>

现在,该应用将在列表中显示每个产品的名称和描述。请注意,最后一项产品没有描述段落。Angular 不会创建 ​<p>​ 元素,因为此产品的 description 属性为空。

添加一个按钮,以便用户可以共享产品。将按钮的 ​click ​事件绑定到 ​product-list.component.ts​ 中的 ​share()​ 方法。事件绑定要在此事件用一组圆括号 ​( )​ 括起来,就比如 ​<button>​ 元素上的 ​(click)​。
<h2>Products</h2>
<div *ngFor="let product of products">
<h3>
<a [title]="product.name + ' details'">
{{ product.name }}
</a>
</h3>
<p *ngIf="product.description">
Description: {{ product.description }}
</p>
<button (click)="share()">
Share
</button>
</div>

每个产品现在都有一个 “Share” 按钮。

单击 “Share” 按钮将触发一条通知,指出 “The product has been shared!”。

在编辑模板时,你已经了解了 Angular 模板的一些最常用的功能。

将数据传递给子组件

目前,产品列表中显示了每个产品的名称和描述。​ProductListComponent ​还定义了一个 ​products ​属性,包含从 ​products.ts​ 的 ​products ​数组导入的各个产品的数据。

下一步是创建一个新的通知功能,该功能会使用来自 ​ProductListComponent ​的产品数据。通知会检查产品的价格,如果价格大于 700 美元,则会显示 Notify Me 按钮,当产品上市销售时,用户可以通过该按钮注册通知。

本节将引导你创建一个子组件 ​ProductAlertsComponent​,该子组件可以从其父组件 ​ProductListComponent ​接收数据。

  1. 点击当前终端上方的加号,新建一个终端,运行命令生成组件。

在新终端中,通过运行以下命令生成一个名为 ​product-alerts​ 的新组件。
ng generate component product-alerts

该生成器会为组件的三个部分创建初始文件:

  • product-alerts.component.ts
  • product-alerts.component.html
  • product-alerts.component.css
打开 ​product-alerts.component.ts​。​@Component()​ 装饰器会指出它后面的类是组件。​@Component()​ 还会提供有关组件的元数据,包括其选择器、模板和样式。
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-product-alerts',
templateUrl: './product-alerts.component.html',
styleUrls: ['./product-alerts.component.css']
})
export class ProductAlertsComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}

@Component()​ 中的主要功能如下:

  • selector​(​app-product-alerts​)用于标识组件。按照惯例,Angular 组件选择器以前缀 ​app-​ 开头,后跟组件名称。
  • 模板和样式文件名引用了组件的 HTML 和 CSS。
  • 这个 ​@Component()​ 定义还导出了类 ​ProductAlertsComponent​,该类会处理组件的功能。
要将 ​ProductAlertsComponent ​设置为接收产品数据,请首先从 ​@angular/core​ 中导入符号 ​Input​。
import { Component, OnInit, Input } from '@angular/core';
import { Product } from '../products';
在 ​ProductAlertsComponent ​类定义中,使用 ​@Input()​ 装饰器定义一个名为 ​product ​的属性。 ​@Input()​ 装饰器指出此属性值要从本组件的父组件 ​ProductListComponent ​中传入。
export class ProductAlertsComponent implements OnInit {
@Input() product!: Product;
constructor() { }
ngOnInit() {
}
}
打开 ​product-alerts.component.html​ 并将占位符段落替换为 Notify Me 按钮,如果产品价格超过 700 美元,就会出现此按钮。
<p *ngIf="product && product.price > 700">
<button>Notify Me</button>
</p>
生成器会自动把 ​ProductAlertsComponent ​添加到 ​AppModule ​中,以便它能用于本应用的其它组件中。
import { ProductAlertsComponent } from './product-alerts/product-alerts.component';
@NgModule({
declarations: [
AppComponent,
TopBarComponent,
ProductListComponent,
ProductAlertsComponent,
],
最后,要将 ​ProductAlertsComponent ​显示为 ​ProductListComponent ​的子级,请将 ​<app-product-alerts>​ 元素添加到 ​product-list.component.html​ 中。使用属性绑定将当前产品作为输入传给此组件。
<button (click)="share()">
Share
</button>
<app-product-alerts
[product]="product">
</app-product-alerts>

这个新的产品通知组件将产品作为产品列表中的输入。使用该输入,它将根据产品的价格显示或隐藏 Notify Me 按钮。Phone XL 的价格超过了 700 美元,因此该产品上会显示 Notify Me 按钮。

将数据传递到父组件

为了使 Notify Me 按钮起作用,子组件需要通知并将数据传递给父组件。当用户单击 Notify Me 时 ​ProductAlertsComponent ​需要引发一个事件,并且 ​ProductListComponent ​需要响应此事件。

在新建组件时,Angular 生成器会包含一个空的 ​constructor()​、​OnInit ​接口和 ​ngOnInit()​ 方法。 由于这些步骤不会使用它们,下列范例代码中都省略了它们,以求简洁。

  1. 在 ​product-alerts.component.ts​ 中,从 ​@angular/core​ 导入符号 ​Output ​和 ​EventEmitter​。
import { Component, Input, Output, EventEmitter } from '@angular/core';
import { Product } from '../products';
在组件类中,使用 ​@Output()​ 装饰器和 ​EventEmitter()​ 的实例定义一个名为 ​notify ​的属性。使用 ​@Output()​ 配置 ​ProductAlertsComponent​,这会让 ​ProductAlertsComponent ​在 ​notify ​属性的值发生变化时引发一个事件。
export class ProductAlertsComponent {
@Input() product: Product | undefined;
@Output() notify = new EventEmitter();
}
在 ​product-alerts.component.html​ 中,修改 Notify Me 按钮,增加事件绑定,并调用 ​notify.emit()​ 方法。
<p *ngIf="product && product.price > 700">
<button (click)="notify.emit()">Notify Me</button>
</p>
定义用户单击按钮时发生的行为。当子组件引发事件时,父组件 ​ProductListComponent​(而不是 ​ProductAlertsComponent​)会采取行动。在 ​product-list.component.ts​ 中,定义一个 ​onNotify()​ 方法,类似于 ​share()​ 方法。
export class ProductListComponent {
products = products;
share() {
window.alert('The product has been shared!');
}
onNotify() {
window.alert('You will be notified when the product goes on sale');
}
}
更新 ​ProductListComponent​,以从 ​ProductAlertsComponent ​中接收数据。

在 ​product-list.component.html​ 中,将 ​<app-product-alerts>​ 绑定到产品列表组件的 ​onNotify()​ 方法。​<app-product-alerts>​ 会显示 Notify Me 按钮的内容。

<button (click)="share()">
Share
</button>
<app-product-alerts
[product]="product"
(notify)="onNotify()">
</app-product-alerts>
单击 Notify Me 按钮以触发一条通知,内容为:"You will be notified when the product goes on sale"。