你好!我希望您已经阅读了我们有关 Angular 组件和路由的教程。在这篇文章中,我们将继续讨论 Angular 中的另一个有趣的概念:服务。
如果 Angular 组件是我们应用程序的表示层,那么什么将负责实际获取真实数据并执行业务逻辑?这正是 Angular 服务的用武之地。Angular 服务的作用是获取、组织并最终跨组件共享数据、模型和业务逻辑。
在深入了解 Angular 服务的技术细节之前,让我们先了解一下其功能。这将帮助您了解代码的哪一部分需要放置在组件内,以及哪一部分需要放置在 Angular 服务内。
以下是有关服务的一些重要事实:
服务是使用 @Injectable
装饰器定义的。这告诉 Angular 该服务可以注入到组件或其他服务中。稍后我们将详细讨论注入服务。
服务是保存所有业务逻辑并跨组件共享的地方。这使您的应用程序更具可扩展性和可维护性。通常,服务也是与后端交互的正确位置。例如,如果您需要进行AJAX调用,可以在服务内部创建完成调用的方法。
服务是单例类。您的 Angular 应用程序中只会运行特定服务的单个实例。
什么是服务?
Angular 中的服务是在应用程序的生命周期中仅实例化一次的对象。服务接收和维护的数据可以在整个应用程序中使用。这意味着组件可以随时从服务获取数据。 依赖注入用于在组件内部引入服务。
让我们尝试了解如何创建服务并在 Angular 组件中使用它。您可以在我们的 GitHub 存储库中找到该项目的完整源代码。
获得源代码后,导航到项目目录并使用 npm install
安装所需的依赖项。安装依赖项后,通过键入以下命令启动应用程序:
ng serve
您应该让应用程序在 https://localhost:4200/.
上运行
我们项目的整体文件夹结构如下。
src --app ----components ------employee.component.css ------employee.component.html ------employee.component.ts ----services ------employee.service.spec.ts ------employee.service.ts ------employeeDetails.service.ts --app.routing.module.ts --app.component.css --app.component.html --app.component.spec.ts --app.component.ts --app.module.ts --assets --index.html --tsconfig.json
1.构建服务的骨架
在 Angular 中创建服务有两种方法:
- 在项目内手动创建文件夹和文件。
- 使用
ng g service
命令自动创建服务。使用此方法时,您将在所选目录中自动获取 .service.ts 和 .service.spec.ts 文件。
ng g service components/employee
2. 创建服务
现在,.service.ts 文件已在您的项目结构中创建,是时候填充服务的内容了。为此,您必须决定服务需要做什么。请记住,您可以拥有多个服务,每个服务都执行特定的业务操作。在我们的例子中,我们将使用 employee.service.ts 将静态角色列表返回给使用它的任何组件。
在employee.service.ts中输入以下代码。
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root', }) export class EmployeeService { role = [ {'id':'1', 'type':'admin'}, {'id':'2', 'type':'engineer'}, {'id':'3', 'type':'sales'}, {'id':'4', 'type':'human_resources'} ] getRole(){ return this.role; } }
此服务仅向应用程序返回角色的静态列表。让我们逐行解码该服务。
- 我们从
@angular/core
库导入Injectable
。这一点至关重要,因为我们的服务将被使用或注入到组件中。@Injectable
指令允许我们识别服务。 - 接下来,我们应用
@Injectable
装饰器。@Injectable
的providedIn
属性指定注入器的可用位置。大多数时候,root
被指定为它的值。这意味着可以在应用程序级别注入服务。其他选项为any
、platform
、null
或Type
。 - 我们创建一个类组件,名称为
EmployeeService
。该类有一个方法getRole
,它返回一个静态对象数组。
3.创建组件
如前所述,Angular 中的服务用于保存应用程序的业务逻辑。为了向查看者显示数据,我们需要一个表示层。这就是传统的基于类的 Angular 组件的用武之地,它是使用装饰器 @Component
创建的。
您可以在本系列的上一篇文章中了解有关 Angular 组件的更多信息。它将帮助您理解 Angular 组件并创建您自己的组件。创建文件 employee.component.ts 并向其中添加以下代码:
import { Component, OnInit } from '@angular/core'; import { EmployeeService } from '../services/employee.service'; @Component({ selector: 'employee', templateUrl: './employee.component.html' }) export class EmployeeComponent implements OnInit { role: any; constructor(private employeeService: EmployeeService) { } ngOnInit(): void { this.role = this.employeeService.getRole() } }
让我们分解一下:
- 导入
@Component
装饰器并调用它。我们指定'employee'
作为选择器,并提供一个指向描述组件视图的 HTML 的模板 URL。 - 声明组件类并指定它实现
OnInit
。因此,我们可以定义一个ngOnInit
事件处理程序,该处理程序将在创建组件时调用。 - 为了使用我们的服务,必须在构造函数内声明它。在我们的例子中,您将在构造函数中看到
private employeeService: EmployeeService
。通过此步骤,我们将使该服务可以跨组件访问。 - 由于我们的目标是在创建员工组件时加载角色,因此我们在
ngOnInit
中获取数据。
这可以变得更简单吗?由于该服务是一个单例类,因此可以在多个组件之间重用,而不会造成任何性能损失。
4.创建视图
现在我们的组件中有数据了,让我们构建一个简单的 employee.component.html 文件来迭代角色并显示它们。下面,我们使用 *ngFor
来迭代角色,并仅向用户显示类型。
<h3>Data from employee.service</h3> <ul> <li *ngFor = "let role of roles">{{role.type}}</li> </ul>
5.运行项目
在项目启动并运行之前我们只剩下一步了。我们需要确保 employee.component.ts 文件包含在 @NgModule
指令内的声明列表中。
如下所示,EmployeeComponent
已添加到 app.module.ts 文件中。
//app.module.ts import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { EmployeeComponent } from './components/employee.component'; @NgModule({ declarations: [ AppComponent, EmployeeComponent ], imports: [ BrowserModule, AppRoutingModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
有趣的是,我们尚未将该服务添加到我们的提供商列表中,但我们能够成功使用该服务。为什么?因为我们已经指定在应用程序的根级别提供服务(即使用 providedIn: 'root'
参数)。但是,请继续阅读以了解有关我们确实需要在 @NgModule
的 providers
数组中提及服务的场景的更多信息。
此外,我们还需要将 employee
元素添加到 app.component.html 文件中。
<h1> Tutorial: Angular Services </h1> <employee></employee> <router-outlet></router-outlet>
如果我们到目前为止运行我们的应用程序,它将如下所示:
6.从服务动态获取数据
现在,我们将获取特定于 employee.component.ts 的数据。
让我们创建一个新服务来从 API 获取数据。
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; @Injectable() export class EmployeDetailsService { fetchEmployeeDetailsURL = 'https://reqres.in/api/users?page=2' constructor(private http: HttpClient) { } fetchEmployeeDetails = () => { return this.http.get(this.fetchEmployeeDetailsURL); } }
现在,让我们逐行理解我们的代码。
- 由于我们要通过 AJAX 调用获取数据,因此导入
HttpClient
非常重要。如果您是HttpClient
的新手,您可以在本系列的另一篇文章中了解更多信息。 - 在我们的
EmployeeDetailsService
中,我们没有指定provideIn
参数。这意味着我们需要执行额外的步骤来让整个应用程序了解我们的可注入服务。您将在下一步中了解这一点。 -
HttpClient
本身就是一个可注入服务。在构造函数中声明它,以便将其注入到组件中。在fetchEmployeeDetails
方法中,我们将使用HttpClient.get
方法从 URL 获取数据。
7. 在 app.module 中注册服务
与我们的第一个服务不同,我们在 app.module.ts 中注册 EmployeeDetailsService
至关重要,因为我们尚未在根级别声明可注入。这是更新后的 app.module.ts 文件:
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { HttpClientModule } from '@angular/common/http'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { EmployeeComponent } from './components/employee.component'; import { EmployeDetailsService } from './services/employeeDetails.service'; @NgModule({ declarations: [ AppComponent, EmployeeComponent ], imports: [ BrowserModule, AppRoutingModule, HttpClientModule ], providers: [ EmployeDetailsService], bootstrap: [AppComponent] }) export class AppModule { }
如果您密切关注,您可能会注意到两个重要的变化:
- 在我们的
app.module.ts
文件中,我们需要将EmployeDetailsService
包含在Providers
列表中。 - 我们需要从
@angular/common/http
导入HttpClientModule
。HttpClientModule
必须包含在我们的imports
列表中。
就是这样 - 我们现在准备在组件中使用 EmployeeDetailsService
。
8.获取动态数据
为了适应新服务,我们将对组件进行一些更改。
添加一个按钮来加载数据
首先,我们将在视图中添加一个按钮。当我们单击此按钮时,将通过 AJAX 调用加载数据。这是更新后的employee.component.html文件:
<h3>Data from employee.service</h3> <ul> <li *ngFor = "let role of roles">{{role.type}}</li> </ul> <button (click)="loadEmployeeDetails()">Load Employee Details</button> <ul> <li *ngFor = "let employee of employeeDetails">{{employee.email}}</li> </ul>
订阅Getter函数
接下来订阅EmployeDetailsService
中的getter函数。为此,我们将 EmployeDetailsService
添加到 employee.component.ts 中的构造函数中:
import { Component, OnInit } from '@angular/core'; import { EmployeeService } from '../services/employee.service'; import { EmployeDetailsService } from '../services/employeeDetails.service'; @Component({ selector: 'employee', templateUrl: './employee.component.html' }) export class EmployeeComponent implements OnInit { roles: any; employeeDetails: any; constructor(private employeeService: EmployeeService, private employeeDetailsService: EmployeDetailsService) { } ngOnInit(): void { this.roles = this.employeeService.getRole() } loadEmployeeDetails = () => { this.employeeDetailsService.fetchEmployeeDetails() .subscribe((response:any)=>{ this.employeeDetails = response.data; }) } }
完成此更改后,单击 LoadEmployeeDetails
按钮,我们将看到以下视图。
结论
给你!我们已经逐步构建了一个可以处理静态和动态数据的 Angular 服务。现在,您应该能够构建自己的 Angular 服务并使用它们通过 AJAX 调用获取数据。您甚至可以以更可重用的方式实现业务逻辑。
2、本站所有文章、图片、资源等如果未标明原创,均为收集自互联网公开资源;分享的图片、资源、视频等,出镜模特均为成年女性正常写真内容,版权归原作者所有,仅作为个人学习、研究以及欣赏!如有涉及下载请24小时内删除;
3、如果您发现本站上有侵犯您的权益的作品,请与我们取得联系,我们会及时修改、删除并致以最深的歉意。邮箱: i-hu#(#换@)foxmail.com