本章基于以一個(gè)基本 Angular 應(yīng)用快速上手的第二步 —— 添加導(dǎo)航。 在此開(kāi)發(fā)階段,本商店應(yīng)用具有一個(gè)包含兩個(gè)視圖的商品名錄:商品列表和商品詳情。用戶(hù)點(diǎn)擊清單中的某個(gè)商品名稱(chēng),就會(huì)在新視圖中看到具有專(zhuān)門(mén)的 URL 或路由的詳情頁(yè)。
本頁(yè)將指導(dǎo)你分三個(gè)步驟創(chuàng)建購(gòu)物車(chē):
HttpClient
?從 ?.json
? 文件中檢索配送數(shù)據(jù)來(lái)取得購(gòu)物車(chē)中這些商品的運(yùn)費(fèi)。在 Angular 中, 服務(wù)是類(lèi)的一個(gè)實(shí)例, 借助 Angular 的依賴(lài)注入體系,你可以在應(yīng)用中的任意部分使用它。
現(xiàn)在, 用戶(hù)可以瀏覽產(chǎn)品信息,而應(yīng)用可以模擬分享產(chǎn)品,以及發(fā)出產(chǎn)品變更通知。
下一步是為用戶(hù)提供一種把產(chǎn)品添加到購(gòu)物車(chē)中的方法。 本章節(jié)將帶領(lǐng)你添加一個(gè) Buy 按鈕并且建立一個(gè)購(gòu)物車(chē)服務(wù)以保存購(gòu)物車(chē)中的產(chǎn)品信息。
本節(jié)將引導(dǎo)你創(chuàng)建用于跟蹤添加到購(gòu)物車(chē)的產(chǎn)品的 ?CartService
?。
cart
?服務(wù):ng generate service cart
Product
?接口從 ?./products.ts
? 導(dǎo)入到 ?cart.service.ts
? 文件中,在 ?CartService
?類(lèi)中,定義一個(gè) ?items
?屬性來(lái)存儲(chǔ)購(gòu)物車(chē)中當(dāng)前產(chǎn)品的數(shù)組。import { Product } from './products';
/* . . . */
export class CartService {
items: Product[] = [];
/* . . . */
}
export class CartService {
items: Product[] = [];
/* . . . */
addToCart(product: Product) {
this.items.push(product);
}
getItems() {
return this.items;
}
clearCart() {
this.items = [];
return this.items;
}
/* . . . */
}
addToCart()
? 方法會(huì)將產(chǎn)品附加到 ?items
?數(shù)組中。getItems()
? 方法會(huì)收集用戶(hù)加到購(gòu)物車(chē)中的商品,并返回每個(gè)商品及其數(shù)量。clearCart()
? 方法返回一個(gè)空數(shù)組。本節(jié)會(huì)教你使用 ?CartService
?來(lái)把一個(gè)商品添加到購(gòu)物車(chē)中。
product-details.component.ts
? 中導(dǎo)入購(gòu)物車(chē)服務(wù)。import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Product, products } from '../products';
import { CartService } from '../cart.service';
constructor()
? 中來(lái)注入它。export class ProductDetailsComponent implements OnInit {
constructor(
private route: ActivatedRoute,
private cartService: CartService
) { }
}
addToCart()
? 方法,該方法會(huì)當(dāng)前商品添加到購(gòu)物車(chē)中。export class ProductDetailsComponent implements OnInit {
addToCart(product: Product) {
this.cartService.addToCart(product);
window.alert('Your product has been added to the cart!');
}
}
?addToCart()
? 方法做了如下事情:
CartService
??addToCart()
? 方法去添加產(chǎn)品到購(gòu)物車(chē)中。product-details.component.html
? 中,添加一個(gè)帶有 Buy 標(biāo)簽的按鈕,并且把其 ?click()
? 事件綁定到 ?addToCart()
? 方法上。 這段代碼會(huì)為產(chǎn)品詳情模板添加一個(gè) Buy 按鈕,并把當(dāng)前產(chǎn)品添加到購(gòu)物車(chē)中。<h2>Product Details</h2>
<div *ngIf="product">
<h3>{{ product.name }}</h3>
<h4>{{ product.price | currency }}</h4>
<p>{{ product.description }}</p>
<button (click)="addToCart(product)">Buy</button>
</div>
Buy
?按鈕如預(yù)期般出現(xiàn)了,并且單擊某個(gè)產(chǎn)品的名稱(chēng),以展示其詳情。
為了讓顧客看到他們的購(gòu)物車(chē),你可以用兩步創(chuàng)建購(gòu)物車(chē)視圖:
要?jiǎng)?chuàng)建購(gòu)物車(chē)視圖,可遵循與創(chuàng)建 ?ProductDetailsComponent
?相同的步驟,并且為這個(gè)新組件配置路由。
cart
?的新組件:ng generate component cart
此命令將生成 ?cart.component.ts
? 文件及其關(guān)聯(lián)的模板和樣式文件。
import { Component } from '@angular/core';
@Component({
selector: 'app-cart',
templateUrl: './cart.component.html',
styleUrls: ['./cart.component.css']
})
export class CartComponent {
constructor() { }
}
StackBlitz 還在組件中默認(rèn)生成一個(gè) ?ngOnInit()
? 。對(duì)于本教程,你可以忽略 ?CartComponent
?的 ?ngOnInit()
? 。
CartComponent
? 已添加到 ?app.module.ts
? 中模塊的 ?declarations
?中。import { CartComponent } from './cart/cart.component';
@NgModule({
declarations: [
AppComponent,
TopBarComponent,
ProductListComponent,
ProductAlertsComponent,
ProductDetailsComponent,
CartComponent,
],
app.module.ts
?,為組件 ?CartComponent
?添加一個(gè)路由,其路由為 ?cart
?:@NgModule({
imports: [
BrowserModule,
ReactiveFormsModule,
RouterModule.forRoot([
{ path: '', component: ProductListComponent },
{ path: 'products/:productId', component: ProductDetailsComponent },
{ path: 'cart', component: CartComponent },
])
],
/cart
?。 在 ?top-bar.component.html
? 中添加一個(gè)指向 ?/cart
? 的 ?routerLink
?指令。<a routerLink="/cart" class="button fancy-button">
<i class="material-icons">shopping_cart</i>Checkout
</a>
https://getting-started.stackblitz.io/cart
?,其中的 getting-started.stackblitz.io 部分可能與你的 StackBlitz 項(xiàng)目不同。
本節(jié)將告訴你如何修改購(gòu)物車(chē)組件以使用購(gòu)物車(chē)服務(wù)來(lái)顯示購(gòu)物車(chē)中的商品。
cart.component.ts
? 中,從 ?cart.service.ts
? 文件中導(dǎo)入 ?CartService
?。import { Component } from '@angular/core';
import { CartService } from '../cart.service';
CartService
?,以便購(gòu)物車(chē)組件可以使用它。export class CartComponent {
constructor(
private cartService: CartService
) { }
}
items
?屬性,以便把商品存放在購(gòu)物車(chē)中。export class CartComponent {
items = this.cartService.getItems();
constructor(
private cartService: CartService
) { }
}
這段代碼使用 ?CartService
?的 ?getItems()
? 方法來(lái)設(shè)置條目。
*ngFor
? 的 ?<div>
? 來(lái)顯示每個(gè)購(gòu)物車(chē)商品的名字和價(jià)格。生成的 ?CartComponent
?模板如下:
<h3>Cart</h3>
<div class="cart-item" *ngFor="let item of items">
<span>{{ item.name }}</span>
<span>{{ item.price | currency }}</span>
</div>
服務(wù)器通常采用流的形式返回?cái)?shù)據(jù)。 流是很有用的,因?yàn)樗鼈兛梢院苋菀椎剞D(zhuǎn)換返回的數(shù)據(jù),也可以修改你請(qǐng)求數(shù)據(jù)的方式。 Angular 的 HTTP 客戶(hù)端( ?HttpClient
?)是一種內(nèi)置的方式,可以從外部 API 中獲取數(shù)據(jù),并以流的形式提供給你的應(yīng)用。
本節(jié)會(huì)為你展示如何使用 ?HttpClient
?從外部文件中檢索運(yùn)費(fèi)。
在本指南的 StackBlitz 應(yīng)用中,通過(guò) ?assets/shipping.json
? 文件提供了一些預(yù)定義的配送數(shù)據(jù)。你可以利用這些數(shù)據(jù)為購(gòu)物車(chē)中的商品添加運(yùn)費(fèi)。
[
{
"type": "Overnight",
"price": 25.99
},
{
"type": "2-Day",
"price": 9.99
},
{
"type": "Postal",
"price": 2.99
}
]
要使用 Angular 的 HTTP 客戶(hù)端之前,你必須先配置你的應(yīng)用來(lái)使用 ?HttpClientModule
?。
Angular 的 ?HttpClientModule
?中注冊(cè)了在整個(gè)應(yīng)用中使用 ?HttpClient
?服務(wù)的單個(gè)實(shí)例所需的服務(wù)提供者。
app.module.ts
? 的頂部從 ?@angular/common/http
? 包中導(dǎo)入 ?HttpClientModule
?以及其它導(dǎo)入項(xiàng)。 由于有很多其它導(dǎo)入項(xiàng),因此這里的代碼片段省略它們,以保持簡(jiǎn)潔。請(qǐng)確?,F(xiàn)有的導(dǎo)入都還在原地。import { HttpClientModule } from '@angular/common/http';
HttpClientModule
?添加到 ?AppModule
??@NgModule()
? 的 ?imports
?數(shù)組中,以便全局注冊(cè) Angular 的 ?HttpClient
?。@NgModule({
imports: [
BrowserModule,
HttpClientModule,
ReactiveFormsModule,
RouterModule.forRoot([
{ path: '', component: ProductListComponent },
{ path: 'products/:productId', component: ProductDetailsComponent },
{ path: 'cart', component: CartComponent },
])
],
declarations: [
AppComponent,
TopBarComponent,
ProductListComponent,
ProductAlertsComponent,
ProductDetailsComponent,
CartComponent,
],
bootstrap: [
AppComponent
]
})
export class AppModule { }
下一步是注入 ?HttpClient
?服務(wù)到你的服務(wù)中, 這樣你的應(yīng)用可以獲取數(shù)據(jù)并且與外部API和資源互動(dòng)。
@angular/common/http
? 包中導(dǎo)入 ?HttpClient
?。import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Product } from './products';
HttpClient
?注入到 ?CartService
?的構(gòu)造函數(shù)中:export class CartService {
items: Product[] = [];
constructor(
private http: HttpClient
) {}
/* . . . */
}
要從 ?shapping.json
? 中得到商品數(shù)據(jù), 你可以使用 ?HttpClient
??get()
? 方法。
cart.service.ts
? 中 ?clearCart()
? 方法下面,定義一個(gè)新的 ?getShippingPrices()
? 方法,該方法會(huì)調(diào)用 ?HttpClient#get()
?方法。export class CartService {
/* . . . */
getShippingPrices() {
return this.http.get<{type: string, price: number}[]>('/assets/shipping.json');
}
}
現(xiàn)在你的應(yīng)用已經(jīng)可以檢索配送數(shù)據(jù)了,你還要?jiǎng)?chuàng)建一個(gè)配送組件和相關(guān)的模板。
shipping
?的組件:ng generate component shipping
右鍵單擊 ?app
?文件夾,選擇 Angular Generator 和 Component 來(lái)生成一個(gè)名為 ?shipping
?的新組件。
import { Component } from '@angular/core';
@Component({
selector: 'app-shipping',
templateUrl: './shipping.component.html',
styleUrls: ['./shipping.component.css']
})
export class ShippingComponent {
constructor() { }
}
app.module.ts
? 中,添加一個(gè)配送路由。其 ?path
?為 ?shipping
?,其 component 為 ?ShippingComponent
?。@NgModule({
imports: [
BrowserModule,
HttpClientModule,
ReactiveFormsModule,
RouterModule.forRoot([
{ path: '', component: ProductListComponent },
{ path: 'products/:productId', component: ProductDetailsComponent },
{ path: 'cart', component: CartComponent },
{ path: 'shipping', component: ShippingComponent },
])
],
declarations: [
AppComponent,
TopBarComponent,
ProductListComponent,
ProductAlertsComponent,
ProductDetailsComponent,
CartComponent,
ShippingComponent
],
bootstrap: [
AppComponent
]
})
export class AppModule { }
新的配送組件尚未鏈接到任何其它組件,但你可以通過(guò)輸入其路由指定的 URL 在預(yù)覽窗格中看到它的模板。該 URL 具有以下模式:?https://angular-ynqttp--4200.local.webcontainer.io/shipping
? ,其中的 gets-started.stackblitz.io 部分可能與你的 StackBlitz 項(xiàng)目不同。
這個(gè)章節(jié)將指導(dǎo)你修改 ?ShappingComponent
?以通過(guò)HTTP從 ?shipping.json
? 文件中提取商品數(shù)據(jù)。
shipping.component.ts
? 中導(dǎo)入 ?CartService
?。import { Component } from '@angular/core';
import { CartService } from '../cart.service';
ShippingComponent
?的 ?constructor()
? 構(gòu)造函數(shù)中:constructor(private cartService: CartService) { }
shippingCosts
?屬性,并從 ?CartService
?中利用購(gòu)物車(chē)服務(wù)的 ?getShippingPrices()
? 方法設(shè)置它。export class ShippingComponent {
shippingCosts = this.cartService.getShippingPrices();
}
async
?管道修改配送組件的模板,以顯示配送類(lèi)型和價(jià)格:<h3>Shipping Prices</h3>
<div class="shipping-item" *ngFor="let shipping of shippingCosts | async">
<span>{{ shipping.type }}</span>
<span>{{ shipping.price | currency }}</span>
</div>
?async
?管道從數(shù)據(jù)流中返回最新值,并在所屬組件的生命期內(nèi)持續(xù)返回。當(dāng) Angular 銷(xiāo)毀該組件時(shí),?async
?管道會(huì)自動(dòng)停止。
<h3>Cart</h3>
<p>
<a routerLink="/shipping">Shipping Prices</a>
</p>
<div class="cart-item" *ngFor="let item of items">
<span>{{ item.name }}</span>
<span>{{ item.price | currency }}</span>
</div>
點(diǎn)擊此鏈接可以導(dǎo)航到運(yùn)費(fèi)頁(yè)。
更多建議: