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