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>

运行效果

增加按钮


删除数据

相关推荐
Carlos_sam7 分钟前
OpenLayers:ol-wind之渲染风场图全解析
前端·javascript
拾光拾趣录16 分钟前
闭包:从“变量怎么还没死”到写出真正健壮的模块
前端·javascript
拾光拾趣录36 分钟前
for..in 和 Object.keys 的区别:从“遍历对象属性的坑”说起
前端·javascript
OpenTiny社区1 小时前
把 SearchBox 塞进项目,搜索转化率怒涨 400%?
前端·vue.js·github
编程猪猪侠1 小时前
Tailwind CSS 自定义工具类与主题配置指南
前端·css
qhd吴飞1 小时前
mybatis 差异更新法
java·前端·mybatis
YGY Webgis糕手之路2 小时前
OpenLayers 快速入门(九)Extent 介绍
前端·经验分享·笔记·vue·web
患得患失9492 小时前
【前端】【vueDevTools】使用 vueDevTools 插件并修改默认打开编辑器
前端·编辑器
ReturnTrue8682 小时前
Vue路由状态持久化方案,优雅实现记住表单历史搜索记录!
前端·vue.js
UncleKyrie2 小时前
一个浏览器插件帮你查看Figma设计稿代码图片和转码
前端