从零开始学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'});

当尝试执行时,因为不存在价格而导致出现错误。

001.png

另外,即使添加不存在的元素,也会出现错误。

this.testMethod({name: 'test', price: 100, extend: 'feawfeaw'});
002.png

列举

同样,一个意外常用的是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这些用于指定变量和方法作用域的修饰符可用。

修飾子スコープ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 来检查其行为。

003.png

到目前为止的提交

从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。

004.png

迄今为止的提交

整理

这次学习了Typescript的基础知识,以及使用服务类进行数据管理的方法。

我們提到了一個非同步處理的概念叫做 Observable。
可能一開始會覺得有點難以理解,但隨著使用的經驗增加,你會慢慢理解的(我一開始也感到困惑,但不知不覺中開始理解了),所以首先讓我們開始使用它吧。

下一次,我们会讲解如何在Angular中创建表单以及如何接收点击事件等内容。

使用Angular,教你1个月内从零开始创建可用的服务( 第6讲:使用ngModel创建表单 )。

入门文章目录

「Angular入門 未経験から1ヶ月でサービス作れるようにする」のために、多くの記事があるため、まとめ記事を作成しています。
https://qiita.com/seteen/items/43908e33e08a39612a07

广告
将在 10 秒后关闭
bannerAds