Angular中创建和使用服务

Angular中的服务


文章目录


前言

Angular 服务是 Angular 应用程序中用于封装可重用逻辑的类。服务在应用程序的多个组件之间共享数据和功能,而不依赖于应用程序的UI。服务可以用于诸如数据处理、与后端通信、用户身份验证等任务。

Angular 把数据与业务进行了抽离,希望我们能够单一的专注于数据的处理和数据的展示。所以就建立了服务的概念。这里的服务不是后台中的服务,本质是函数的封装。封装很多方法,对数据进行处理和返回。

以下是 Angular 服务的一些关键点:

  • 依赖注入: Angular服务通过依赖注入(DI)系统在应用程序中使用。这意味着组件或其他服务可以请求服务的实例,而不需要知道如何创建这些实例。
  • 单例模式: 默认情况下,Angular 服务是单例的,这意味着每个服务类在应用程序中只有一个实例。
  • 惰性初始化: 服务只在第一次请求时创建,之后每次请求都会返回同一个实例。
  • 服务定义: 使用 @Injectable 装饰器定义服务,并通过 providedIn 属性或在模块中手动添加来指定服务的作用域。
  • 服务使用: 组件或其他服务可以通过构造函数注入来使用服务。

一、创建服务

使用命令创建

bash 复制代码
ng g service 服务名

在这里我在services目录下创建一个data服务

bash 复制代码
ng g service services/data

这个组件就创建好了。

二、使用服务

使用命令创建data组件

bash 复制代码
ng g component components/data

在服务中写一些功能

csharp 复制代码
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'// 这里的'root'意味着服务将在整个应用中可用
})
export class DataService {

  constructor() { }
  // 示例数据 
  private data: any[] = [
    { id: 1, name: 'Item 1' },
    { id: 2, name: 'Item 2' },
    { id: 3, name: 'Item 3' },
    { id: 4, name: 'Item 4' },
    { id: 5, name: 'Item 5' },
    { id: 6, name: 'Item 6' },
    { id: 7, name: 'Item 7' },
    { id: 8, name: 'Item 8' },
    { id: 9, name: 'Item 9' },
    { id: 10, name: 'Item 10' }
  ];
  
  // 获取数据的方法  
  getData(): any[] { 
    console.log('DataService: getData() called'  + '   ' +this.data.length);
    return this.data;  
  }  
  
  // 添加数据的方法  
  addData(item: any) {  
    this.data.push(item);  
  } 

  // 移除数据的方法  
  removeData(item: any) {  
    this.data = this.data.filter(x => x !== item);
  } 
}

在 Angular 中,@Injectable 装饰器的 providedIn 属性用于指定服务的作用域,即在哪里提供这个服务的实例。providedIn: 'root' 表示该服务是单例的,并且由 Angular 的根模块(通常是 AppModule)提供。

除了root,providedIn 还可以有以下几种使用方式:

  • root:服务作为单例在整个应用程序中只有一个实例。这是默认的提供方式,适用于大多数服务。
  • any:服务可以在任何模块中提供,并且可以在多个模块中多次提供,每次提供都将创建一个新的实例。
  • platform:服务只在平台(例如服务器端或 Web Worker)上提供,而不是在浏览器的主渲染线程上。
  • NgModule:服务在特定的 NgModule 中提供。这意味着服务的实例只在该模块及其导入的模块中可用。
  • module:后面跟上具体的模块类,例如 providedIn: MyModule,服务只在该模块及其导入的模块中提供。

还可以使用null,实际上是在告诉 Angular 的依赖注入系统不要自动提供这个服务,这样做之后,你需要手动在模块的 providers 数组中注册服务。

csharp 复制代码
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: null // 显式地告诉 Angular 不要自动提供这个服务
})
export class MyService {
  // 服务逻辑
}

在模块中手动添加这个服务到 providers 数组中:

csharp 复制代码
import { NgModule } from '@angular/core';
import { MyService } from './my.service';

@NgModule({
  // ... 其他模块元数据
  providers: [MyService] // 手动提供服务
})
export class MyModule {
  // 模块逻辑
}

使用 providedIn: null 主要有几个用途:

  • 控制服务的作用域:你想要控制服务实例的作用域,比如仅在一个特定的模块及其子模块中可用。
  • 避免单例模式:虽然 Angular 默认创建服务的单例,但通过手动提供服务,你可以在不同模块中创建服务的多个实例。
  • 延迟提供服务:在某些情况下,你可能希望延迟服务的创建,直到它实际上被需要,这可以通过手动提供服务来实现。
  • 兼容性:如果你正在维护一个旧的 Angular 应用程序,并且想要保持对旧行为的兼容性,使用 null 可以给你更多的控制。

总的来说,使用 null 提供服务是一种更明确和手动的方法,它允许开发者更精确地控制服务的生命周期和作用域。然而,这也意味着你需要更仔细地管理服务的注册和使用,以避免错误或不一致的行为。

要使用服务,首先需要将其注入到组件中。你可以通过组件的构造函数注入服务:

csharp 复制代码
  constructor(private dataService: DataService) { }

data.component.ts

csharp 复制代码
import { Component } from '@angular/core';
import { DataService } from '../../services/data.service';
import { CommonModule } from '@angular/common';

@Component({
  selector: 'app-data',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './data.component.html',
  styleUrl: './data.component.css'
})
export class DataComponent {

  items: any[]=[];

  constructor(private dataService: DataService) { }

  ngOnInit() :void{
    this.items = this.dataService.getData(); // 调用服务方法获取数据  
  }

  addItem(): void {
    let iCount = this.items.length+1;
    console.log(iCount);
    this.dataService.addData( { id: iCount, name: 'Item ' + iCount})
    alert('Item ' + iCount+' 添加成功');
  }

  removeItem(): void {
    if(this.items.length===0)
    {
      alert('没有数据可删');
      return;
    }
    console.log('删除前'+ this.items.length);
    let lastItem = this.items[this.items.length-1];
    this.dataService.removeData(lastItem);
    this.items = this.dataService.getData();
    console.log('删除后'+ this.items.length);
    alert(lastItem.name+' 删除成功');
  }
}

在imports里面加上CommonModule,不然html里面的*ngFor会有提醒。

data.component.html

csharp 复制代码
<p>data works!</p>

<div>
    <button (click)="addItem()">增加数据</button>
    <button (click)="removeItem()">删除数据</button>
</div>

<div *ngFor="let item of items" >  
    <p>{{ item.name }}</p>  
</div>
<!-- @for (item of items; track $index) {

    <p>{{ item.name }}</p>  
} -->
<p>data works end!</p>

app.component.ts

csharp 复制代码
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { DataComponent } from './components/data/data.component';

@Component({
    selector: 'app-root',
    standalone: true,
    templateUrl: './app.component.html',
    styleUrl: './app.component.css',
    imports: [RouterOutlet, DataComponent]
})
export class AppComponent {
  title = 'first-component';
}

app.component.html

csharp 复制代码
<p>这个是app</p>

<app-data></app-data>

运行效果

增加按钮


删除数据

相关推荐
正小安1 小时前
如何在微信小程序中实现分包加载和预下载
前端·微信小程序·小程序
_.Switch3 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光3 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   3 小时前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发
长路 ㅤ   3 小时前
vue-live2d看板娘集成方案设计使用教程
前端·javascript·vue.js·live2d
Fan_web3 小时前
jQuery——事件委托
开发语言·前端·javascript·css·jquery
安冬的码畜日常3 小时前
【CSS in Depth 2 精译_044】第七章 响应式设计概述
前端·css·css3·html5·响应式设计·响应式
莹雨潇潇4 小时前
Docker 快速入门(Ubuntu版)
java·前端·docker·容器
Jiaberrr4 小时前
Element UI教程:如何将Radio单选框的圆框改为方框
前端·javascript·vue.js·ui·elementui
Tiffany_Ho5 小时前
【TypeScript】知识点梳理(三)
前端·typescript