从零开始学Angular,仅需一个月即可制作服务。第五部分:服务和Typescript基础
上次是。
-
- Angularでのデータ管理の基礎(モデル作成)
-
- HTMLでの分岐(*ngIf)
- HTMLでのループ(*ngFor)
学会了。
本文旨在讨论
-
- ES6とTypescriptの基礎
Typescriptの型定義について
Angularでのデータ管理の基礎2
サービスクラスの作成
我会继续做下去。
这篇文章的源代码
https://github.com/seteen/AngularGuides/tree/第5个入门
TypeScript的基础
在Angular中,我们使用Typescript。
由於以後我們將使用更多的TypeScript代碼,因此現在就讓我們學習基礎知識吧。
类型的规定 de
我們已經多次提到過,TypeScript 中,我們會為每個變數和方法定義類型。
export class Test {
name: string; // <- これがインスタンス変数
toString(input: string): string { // <- これがインスタンスメソッド
return input;
}
}
用中文原生语言释义:这样一来,
-
- 変数定義は 変数名: 型
メソッド定義は メソッド名(引数名: 引数名の型): メソッドの型 { メソッドの内容 }
需要写成意思
种类的类型
在Typescript中常常使用的类型有
-
- string : 文字列
-
- number : 数値
-
- boolean : 真偽値
- void: 何も返さないメソッドの型
这些是自己定义的类也是类型。另外,对于数组的表示方法是在类型后面加上 [],例如 string[]。
names: string[]
另外,还有一种名为 “任意” 的类型,表示 “无论什么都可以”。
当不知道应选择哪种类型时,可以考虑这个最后的选择。
界面
在Typescript中,有接口(Interface)的概念。它可以像Java等语言中的类继承接口一样使用,还可以在方法参数等复杂情况下使用,并且可以对对象的键进行约束。
我们来看个例子。
export interface TestInterface {
name: string;
price: number;
description?: string;
}
有一个叫作「という接口(Interface)」的组件。
testMethod(input: TestInterface): void {
...
}
假设有一个接受TestInterface作为参数的方法。
通过使用Interface,可以对稍复杂的参数进行约束。上述代码的意思是,name和price是必需的,而description带有?,表示它是可选的(可以有也可以没有)。
因此,例如对于这个方法,
this.testMethod({name: 'test'});
当尝试执行时,因为不存在价格而导致出现错误。

另外,即使添加不存在的元素,也会出现错误。
this.testMethod({name: 'test', price: 100, extend: 'feawfeaw'});

列举
同样,一个意外常用的是Enum。当一个变量只能取特定的值时,我们会使用它。例如,作为状态,有非公开(unpublished)和公开(published)两个值,当存在一个变量只能取这两个值时。
export enum Status {
unpublished = 'unpublished',
published = 'published'
}
如果只接收数字,并且取值范围为非公开(0)和公开(1),可以如下所述。
export enum Status {
unpublished,
published
}
总之,如果没有任何指定,将按照从上到下的顺序从0开始分配数值。
作为使用者来说,
export class TestClass {
status: Status;
}
如下所述。 .)
通过这个操作,status变量只能静态地包含Status所定义的值。
注意事项是与枚举等类型相关的限制。
字符串、数字等变量的类型指定以及通过枚举对值的约束,这些只在静态分析时有效。
因此,即使动态地放入不同类型的值,它也不会在此时引发错误。(与Java等不同)
这是因为在运行时,它以 JavaScript 的形式执行,所以无法享受到 TypeScript 的好处。例如,如果在 API 中原本预期是字符串,但实际传入了数值,即使进行赋值也不会报错。
雖然類型的限制很強大,但是也有這樣的情況存在,所以請注意不要過度依賴以至於停止思考。
提示:TypeScript的便捷记法
例如,假设已定义一个名为 params 的变量,
只需写上 { params },它会解析为 { params: params }。
非常方便。
私有的、受保护的、公共的
在TypeScript中,有private,protected,public这些用于指定变量和方法作用域的修饰符可用。
这个修饰符是
export class Test {
private name: string;
protected testMethod(): string {
...
}
}
如果没有指定任何修饰符,则会像这样使用。它将被视为公共(public)。
在Angular中的数据管理基础2
在Angular中,可以使用Service类来管理API访问和跨组件的数据处理。
让我们创建一个ProductService类,把Product的数据管理移到组件之外。
创建服务类
让我们使用Angular CLI来创建服务。
# ng g service shared/services/product
CREATE src/app/shared/services/product.service.spec.ts (380 bytes)
CREATE src/app/shared/services/product.service.ts (136 bytes)
我想在 src/app/shared/services/ 目录中放置服务,所以我将其写成了上述的方式。
让我们看一下创建的文件。虽然spec.ts文件(测试文件)也已经创建了, 但我们暂时不考虑它。
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class ProductService {
constructor() { }
}
@Injectable是一个在服务类中使用的魔法词。
其中包含{ providedIn: ‘root’ },意思是在根级别使用这个服务。
服务类以指定的providedIn单位进行实例化(在这种情况下是根级别,即整个项目),并且一个实例被重复使用。可以认为它类似于单例模式。
我们将添加一个方法来获取产品列表的功能。
最后我们会在这里进行API访问,但现在我们不会进行API访问。
import { Injectable } from '@angular/core';
import { Product } from '../models/product';
import { Observable, of } from 'rxjs/index';
@Injectable({
providedIn: 'root'
})
export class ProductService {
products = [
new Product(1, 'Angular入門書「天地創造の章」', 3800, '神は云った。「Angularあれ」。するとAngularが出来た。'),
new Product(2, 'Angularを覚えたら、年収も上がって、女の子にももてて、人生が変わりました!', 410, '年収300万のSEが、Angularと出会う。それは、小さな会社の社畜が始めた、最初の抵抗だった。'),
new Product(3, '異世界転生から始めるAngular生活(1)', 680,
'スパゲッティの沼でデスマーチ真っ最中の田中。過酷な日々からの現実逃避か彼は、異世界に放り出され、そこでAngularの入門書を拾う。現実逃避でさえ、プログラミングをするしかない彼に待ち受けるのは!?'),
];
constructor() { }
list(): Observable<Product[]> {
return of(this.products);
}
}
已添加了list()方法。类型指定为Observable<Product[]>。
目前情况下,由于没有API通信,所以将使用同步处理,但最终将进行API通信,因此list()方法将变为异步处理。
在Angular中,我们使用RxJS进行异步处理。Observable是RxJS的类,它是异步处理中的主要类。
目前来说,您可以将其视为类似Promise的东西。
这也是RxJS中的方法,它用给定的内容创建一个Observable。
换句话说,上述代码是一个返回 Observable(可观察)类型的产品数组的方法。
更改了 product-list.component.ts。
接下来,我们将修改 `product-list.component.ts` 文件。
import { Component, OnInit } from '@angular/core';
import { Product } from '../../shared/models/product';
import { ProductService } from '../../shared/services/product.service';
@Component({
selector: 'app-product-list',
templateUrl: './product-list.component.html',
styleUrls: ['./product-list.component.scss']
})
export class ProductListComponent implements OnInit {
products: Product[] = null;
constructor(
private productService: ProductService,
) {}
ngOnInit() {
this.productService.list().subscribe((products: Product[]) => {
this.products = products;
});
}
}
最初是在 ngOnInit 函数中创建了一个 Product 数组,但现在改为使用 ProductService。
构造函数的说明
我正在构造函数中调用ProductService的参数。
在Angular中,通过这个描述可以将ProductService注入到组件或服务中。(即所谓的依赖注入)
换句话说,通过这个描述,ProductListComponent 中生成了一个名为 productService 的变量。
ngOnInit 的说明
这个.productService.list()函数会返回一个Observable<Product[]>。
如前述,这将返回一个可观察的产品数组。
“subscribe” 是 Observable 的方法,用于开始观察目标 Observable(开始执行 API 访问的异步处理)。
当观测完成时,将调用subscribe的参数回调方法。这个参数将包含类型为Observable的Product[]中的Product[]。
因此,ProductService的list()方法返回的数组将传递给该方法。
总之,
this.productService.list().subscribe((products: Product[]) => {
这意味着这些产品包含在内。
在这个方法中
this.products = products;
在这里,我们将实例变量赋值给了一个对象。这样一来,我们就可以将产品列表组件(product-list.component.ts)中的产品显示出来,并在视图中进行反映。
但是这次,由于我们删除了之前的“等待3秒”描述,所以行为有一些变化(商品列表会很快显示出来)。
確認動作
让我们通过运行 `ng serve` 并访问 http://localhost:4200/products 来检查其行为。

到目前为止的提交
从product-detail.component.ts文件中使用ProductService。
接下来,让我们对 product-detail.component.ts 进行修改,以便调用 ProductService。
在ProductService中添加一个通过id获取商品的方法。
在ProductService中添加一个get(id)方法。
import { Injectable } from '@angular/core';
import { Product } from '../models/product';
import { Observable, of } from 'rxjs/index';
@Injectable({
providedIn: 'root'
})
export class ProductService {
products = [
new Product(1, 'Angular入門書「天地創造の章」', 3800, '神は云った。「Angularあれ」。するとAngularが出来た。'),
new Product(2, 'Angularを覚えたら、年収も上がって、女の子にももてて、人生が変わりました!', 410, '年収300万のSEが、Angularと出会う。それは、小さな会社の社畜が始めた、最初の抵抗だった。'),
new Product(3, '異世界転生から始めるAngular生活(1)', 680,
'スパゲッティの沼でデスマーチ真っ最中の田中。過酷な日々からの現実逃避か彼は、異世界に放り出され、そこでAngularの入門書を拾う。現実逃避でさえ、プログラミングをするしかない彼に待ち受けるのは!?'),
];
constructor() { }
list(): Observable<Product[]> {
return of(this.products);
}
get(id: number): Observable<Product> {
return of(this.products[id - 1]);
}
}
get(id) 方法是返回指定 id 的 Product 的 Observable。
从 product-detail.component.ts 中的使用
几乎与product-list.components.ts相同。
import { Component, OnInit } from '@angular/core';
import { Product } from '../../shared/models/product';
import { ProductService } from '../../shared/services/product.service';
@Component({
selector: 'app-product-detail',
templateUrl: './product-detail.component.html',
styleUrls: ['./product-detail.component.scss']
})
export class ProductDetailComponent implements OnInit {
product: Product;
constructor(
private productService: ProductService,
) {}
ngOnInit() {
this.productService.get(2).subscribe((product: Product) => {
this.product = product;
});
}
}
constructor にて ProductService の変数を得る
ngOnInit で get(id) を subscribe (観測) して商品を取得しています
あと、特に理由はありませんが、取得するものを 2 に変えました
确认操作
请使用 `ng serve` 命令启动,并访问 http://localhost:4200/products/test。

迄今为止的提交
整理
这次学习了Typescript的基础知识,以及使用服务类进行数据管理的方法。
我們提到了一個非同步處理的概念叫做 Observable。
可能一開始會覺得有點難以理解,但隨著使用的經驗增加,你會慢慢理解的(我一開始也感到困惑,但不知不覺中開始理解了),所以首先讓我們開始使用它吧。
下一次,我们会讲解如何在Angular中创建表单以及如何接收点击事件等内容。
使用Angular,教你1个月内从零开始创建可用的服务( 第6讲:使用ngModel创建表单 )。
入门文章目录
「Angular入門 未経験から1ヶ月でサービス作れるようにする」のために、多くの記事があるため、まとめ記事を作成しています。
https://qiita.com/seteen/items/43908e33e08a39612a07