[Angular 基础] - service 服务

[Angular 基础] - service 服务

之前的笔记就列举三个好了……没想到 Angular 东西这么多(ー ー;)……全加感觉越来越凑字数了

  • [Angular 基础] - 视图封装 & 局部引用 & 父子组件中内容传递

  • [Angular 基础] - 生命周期函数

  • [Angular 基础] - 自定义指令,深入学习 directive


Angular 的 service 如果后端出身的应该很熟悉,它是 Angular 自行管理,并使用 Dependency Injection 去实现的一个类。因此它比较合适使用的场景是,多个嵌套组件需要互相沟通,并需要传递值。

举例说明:

|- a
|  |- b
|  |  |- d
|  |- c
|  |  |- e

这个情况下,a 如果需要和 de 进行沟通的话,那么

  • bc 也需要通过 @Input 去获取从 a 传来的值,并将其传到 de 中去;
  • bc 也需要通过 @Output 去获取从 de 传来的事件,并将其传到 a 中去

这就是一个不可避免的沟通环节。

使用 service 就可以比较有效的解决这个问题

创建一个新的案例

这个案例相对比较简单,就是按照上面的结构创建一个项目。在这个简单的案例里,bc 没有任何作用,只是作为 a <--> da <--> e 之间的承接桥梁。在真实的项目中,bc 的作用可能会包括一些数据处理、选择渲染之类的。

项目结构如下:

❯ tree src/app/
src/app/
├── app.component.css
├── app.component.html
├── app.component.spec.ts
├── app.component.ts
├── app.module.ts
├── b
│   ├── b.component.css
│   ├── b.component.html
│   ├── b.component.ts
│   └── d
│       ├── d.component.css
│       ├── d.component.html
│       └── d.component.ts
└── c├── c.component.css├── c.component.html├── c.component.ts└── e├── e.component.css├── e.component.html└── e.component.ts5 directories, 17 files

a 的实现

这里主要还是传值+绑定事件,具体内容在 [Angular 基础] - 自定义事件 & 自定义属性 里,这里就不多做赘述,直接放代码了:

  • V 层

    <div class="container"><div class="row"><div class="col-xs-12 col-md-8 col-md-offset-2"><app-b [message]="aToD" (messageFromB)="onRecieveMessageFromB"></app-b><app-c [message]="aToE"></app-c></div></div>
    </div>
    
  • VM 层:

    import { Component, EventEmitter, OnInit, Output } from '@angular/core';@Component({selector: 'app-root',templateUrl: './app.component.html',styleUrls: ['./app.component.css'],
    })
    export class AppComponent {aToD = 'message from a to d';aToE = 'message from a to e';@Output() messageFromB = new EventEmitter<string>();onRecieveMessageFromB($event: string): void {this.aToD = $event;console.log('message from b to a: ', $event);}
    }
    

b 的实现

实现基本和 a 一致,这里也就放代码了:

  • V 层

    <div class=""><app-d [message]="message" (messageToB)="onRecieveMessage($event)"></app-d>
    </div>
    
  • VM 层

    import {Component,EventEmitter,Input,OnInit,Output,
    } from '@angular/core';@Component({selector: 'app-b',templateUrl: './b.component.html',styleUrl: './b.component.css',
    })
    export class BComponent implements OnInit {@Input() message: string;@Output() messageToA = new EventEmitter<string>();ngOnInit(): void {}onRecieveMessage($event: string): void {this.message = $event;this.messageToA.emit(this.message);console.log('message from b to a: ', this.message);}
    }
    

d 的实现

  • V 层

    <input type="text" [value]="message" (input)="onChangeText($event)" />
    
  • VM 层

    import {Component,EventEmitter,Input,OnInit,Output,
    } from '@angular/core';@Component({selector: 'app-d',templateUrl: './d.component.html',styleUrl: './d.component.css',
    })
    export class DComponent implements OnInit {@Input() message: string;@Output() messageToB = new EventEmitter<string>();ngOnInit(): void {}onChangeText($event: Event): void {this.message = ($event.target as HTMLInputElement).value;this.messageToB.emit(this.message);console.log('message from d to b: ', this.message);}
    }
    

最后实现效果如下:

在这里插入图片描述

如果说 React 只是将 onChangeHandler 一个个向子组件里传递,做 props drilling,那么 Angular 除了要在 HTML Template 中传值之外,还需要在组件中实现 @Input@Output 去接受从父组件中传下来的值,并且将事件送到父组件中,对比起来操作更加的麻烦

使用 service 代替

这里使用 service 代替上下传递 @Input@Outpu 进行实现

创建 service

这里依旧使用 cli 去创建 service:

❯ ng generate service services/message --skip-tests
CREATE src/app/services/message.service.ts (136 bytes)

此时结构如下:

在这里插入图片描述

实现如下:

import { Injectable } from '@angular/core';@Injectable({providedIn: 'root',
})
export class MessageService {passedMessage = 'message from a to e';constructor() {}updateMessage(msg: string) {this.passedMessage = msg;}
}

具体实现会在下一个 section 说明

调用 service

调用方式是在构造函数中让 Angular 自动使用 dependency injection 实现

a 的修改:
export class AppComponent {// 这里的 dependency injection 是由 angular 实现的constructor(private messageService: MessageService) {}
}
c 的实现
import { Component, DoCheck, Input } from '@angular/core';
import { MessageService } from '../services/message.service';@Component({selector: 'app-c',templateUrl: './c.component.html',styleUrl: './c.component.css',
})
export class CComponent implements DoCheck {message: string;constructor(private messageService: MessageService) {this.message = this.messageService.passedMessage;}ngDoCheck(): void {console.log(this.messageService.passedMessage);}
}

HTML Template 中只需要渲染一个 e 即可:

<app-e></app-e>

⚠️:这里主要是 log 一下 service 中变化的值。因为 message 是一个 primitive,所以想要正确的获取 message 的变化是要使用 Observable 的,目前暂时没有涉及到这个部分,因此只是在 ngDoCheck 中输出一下值,表示当前的变化已经被获取了

e 的实现
import { Component, Input } from '@angular/core';
import { MessageService } from '../../services/message.service';@Component({selector: 'app-e',templateUrl: './e.component.html',styleUrl: './e.component.css',
})
export class EComponent {message: string;constructor(private messageService: MessageService) {this.message = this.messageService.passedMessage;}onChangeText($event: Event): void {this.messageService.updateMessage((<HTMLInputElement>$event.target).value);}
}

最终效果:

在这里插入图片描述

可以看到,对比 a <--> b <--> d 的沟通, a <--> c <--> e 中使用 service 更加的简洁

深入了解 service

Injectable

这个 decorator 在新版的 Angular 是推荐每个 service 都放上,现在默认使用 cli 就会自动带上 Injectable

providedIn 则是挂载的范围,默认情况下挂载的范围是全局。换言之所有的 component 都共享一个 singleton。如果将 providedIn 删除的话,那么 Angular 就可以创建多个 instance

多个 instance & providers

这里首先需要将 Injectable 中的 providedIn 去掉,只保留 @Injectable 这个 decorator 或者去除都行——新版 Angular 是推荐保留 decorator 的

随后需要修改 @Component decorator,这里是修改 B/C 两个组件中的 decorator:

@Component({selector: 'app-b',templateUrl: './b.component.html',styleUrl: './b.component.css',providers: [MessageService],
})

这样当前 component 及其后代 component 都会共享同一个 service:

在这里插入图片描述

⚠️:这里页面显示的(d/e 从 MessageService 中接受的信息)与 log 中是一致的

如果修改 d/e decorator 中的 providers 的话,d/e 二者也会有自己的 service instance:

在这里插入图片描述

⚠️:这里页面显示的(d/e 从 MessageService 中接受的信息)与 log 中是不一致的

这是因为 providers 是 Angular 接受参数用来配置 Dependency Injection 的地方,提供值就会新建一个新的 instance。因此如果想要组件内共享同一个 service 的话,就需要在最近祖先节点修改对应的 providers

👀:传的信息内容我通过 Faker 的随机 lorem 生成,所以每个 service 会不一样

service 注入 service

我这里的实现是两个 service 都会有 @Injectable 这个装饰器,这样的实现会方便一些。MessageService 的实现基本不变,需要修改的就是在构造函数内,通过依赖注入绑定一个 LoggingService,修改如下:

import { Injectable } from '@angular/core';
import { faker } from '@faker-js/faker';
import { LoggingService } from './logging.service';@Injectable()
export class MessageService {passedMessage = faker.lorem.sentence();constructor(private loggingService: LoggingService) {this.loggingService.logMessage('MessageService constructor created message to ' + this.passedMessage);}updateMessage(msg: string) {this.passedMessage = msg;this.loggingService.logMessage('MessageService updated message to ' + msg);}
}

LoggingService 则是一个实现了输出信息的 service:

import { Injectable } from '@angular/core';@Injectable({ providedIn: 'root' })
export class LoggingService {constructor() {}logMessage(msg: string) {console.log(`${msg} received at ${new Date().toLocaleTimeString()}`);}
}

这样每次当 MessageService 被实例化和变动的时候,都会调用一次输出日志方法:

在这里插入图片描述

services 的应用场景

根据案例可以看出来,它可以实现以下几个功能:

  • 数据共享

    不用使用 @Input 进行不同层级的数据传递

  • 状态管理

    这个作用和 React 的 Context 有点相似,在层级内控制状态,并且通过状态进行数据和组件的对应渲染

  • API 交互

    HTTP 请求的抽象实现,比如说实现一个 API 层级的 CRUD 封装,这样所有的组件都可以较为方便的调用

  • 业务逻辑实现

    也是属于功能的一种抽象,如果某些功能不是特定属于几个组件内,那么就可以将其抽离出来进行共享

  • util

    也是属于功能的一种抽象,如果某些功能不是特定属于几个组件内,那么就可以将其抽离出来进行共享

    其中一个例子就是上面实现的 logging util

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/696908.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

请简述你对SpringMVC的理解

SpringMVC是一种基于Java语言开发&#xff0c;实现了WebMVC设计模式&#xff0c;请求驱动类型 的轻量级Web框架。 采用了MVC架构模式的思想&#xff0c;通过把Model&#xff0c;View&#xff0c;Controller分离&#xff0c;将Web层进 行职责解耦&#xff0c;从而把复杂的Web应…

STM32控制数码管从0显示到99

首先 先画电路图吧&#xff01;打开proteus&#xff0c;导入相关器件&#xff0c;绘制电路图。如下&#xff1a;&#xff08;记得要保存啊&#xff01;发现模拟一遍程序就自动退出了&#xff0c;有bug&#xff0c;我是解决不了&#xff0c;所以就是要及时保存&#xff0c;自己重…

计算机组成原理(10)----微程序控制器

目录 1.微程序控制器的设计思想 2.微指令的基本格式 3.微程序控制器的基本结构 &#xff08;1&#xff09;控制存储器CM &#xff08;2&#xff09;CMAR &#xff08;3&#xff09;地址译码 &#xff08;4&#xff09;CMDR &#xff08;5&#xff09;微地址形成部件 &…

31.云原生Istio可观测性之官网Bookinfo应用实战演示

云原生专栏大纲 文章目录 可观测性kiali介绍Overview&#xff08;概观&#xff09;Application&#xff08;应用维度&#xff09;workloads&#xff08;负载维度&#xff09;Services&#xff08;服务维度&#xff09;Istio Config&#xff08;配置维度&#xff09; Kiali部署…

音频声波的主观感受

一、响度 声压是“客观”的&#xff0c;响度是“主观”的。 响度又称音量。人耳感受到的声音强弱&#xff0c;它是人对声音大小的一个主观感觉量。响度的大小决定于声音接收处的波幅&#xff0c;就同一声源来说&#xff0c;波幅传播的愈远&#xff0c;响度愈小…

React18原理: React核心对象之Update、UpdateQueue、Hook、Task对象

Update 与 UpdateQueue 对象 1 ) 概述 在fiber对象中有一个属性 fiber.updateQueue是一个链式队列&#xff08;即使用链表实现的队列存储结构&#xff09;是和页面更新有关的 2 &#xff09;Update对象相关的数据结构 // https://github.com/facebook/react/blob/v18.2.0/pa…

VSCode The preLaunchTask ‘C/C++: clang++ 生成活动文件‘ terminated with exit code -1

更改tasks.json文件里面的type为shell 选择g 选择g&#xff0c;然后点回到text.c&#xff0c;按下F5. 得到结果。 文中内容参考: 从零开始手把手教你配置属于你的VS Code_哔哩哔哩_bilibili https://blog.csdn.net/qq_63872647/article/details/128006861

【EasyV】QGIS转换至EasyV

QGIS转换至EasyV 第一步&#xff1a;导入QGIS第二步 坐标系转换第三步 集合修正第四步 重命名字段第五步 导出WGS geojson坐标第六步 导入EasyV 第一步&#xff1a;导入QGIS 第二步 坐标系转换 第三步 集合修正 第四步 重命名字段 第五步 导出WGS geojson坐标 第六步 导入EasyV…

【vue vue-seamless-scroll】解决vue-seamless-scroll鼠标悬浮才滚动或者只滚动一次就失效的问题

解决问题&#xff1a;使用vue-seamless-scroll发现只有鼠标悬浮上去才滚动&#xff0c;而且滚动一次停止了 目标效果&#xff1a; 解决方案&#xff1a; 最后发现是因为数据需要在页面挂载好就赋值&#xff0c;否则页面在加载完成后&#xff0c;数据无法自动滚动。但因为数据…

c++:蓝桥杯的基础算法2(构造,模拟)+练习巩固

目录 构造 构造的基础概念&#xff1a; 模拟 练习1&#xff1a;扫雷 练习2&#xff1a;灌溉 练习3&#xff1a;回文日期 构造 构造的基础概念&#xff1a; 构造算法是一种用于解决特定问题的算法设计方法。在C语言中&#xff0c;构造算法通常涉及到创建一个函数或类来实…

ARM服务器上部署zookeeper集群

由于ARM服务器上部署zookeeper集群,会存在加载不到主类问题,现在把遇到的问题进行总结下,问题如下: [rootnode206 apache-zookeeper-3.5.10]# bin/zkServer.sh start ZooKeeper JMX enabled by default Using config: /data1/software/apache-zookeeper-3.5.10/bin/../conf/…

四、Burpsuite工具之proxy模块详解-intercept功能

前言&#xff1a; 过了一个年&#xff0c;感觉好久都没有更新了&#xff0c;今天就从burpsuite的更新开始吧。 前面已经说过了burpsuite的安装和proxy代理的配置&#xff0c;今天说一下proxy模块中非常有用的intercept功能。 intercept功能介绍&#xff1a; intercept是拦截…

Spring之AOP源码解析(中)

前言 在上一篇文章中,我们讲解了Spring中那些注解可能会产生AOP动态代理,我们通过源码发现,完成AOP相关操作都和ProxyFactory这个类有密切关系,这一篇我们将围绕这个类继续解析 演示 作用 ProxyFactory采用策略模式生成动态代理对象,具体生成cglib动态代理还是jdk动态代理,…

APP的UI自动化demo(appium+java)

文章目录 appium连接手机java代码实现-第一版第二版-接入testng和隐式等待显示等待 appium连接手机 准备工作 1、查看连接手机模拟器是否连接成功&#xff0c;获取设备名称 执行命令&#xff1a;adb devices 2、查看android内核版本号—>paltformVersion 执行命令&#xf…

Postman接口关联实战解析

在使用postman做接口测试时&#xff0c;有时候后面的接口需要获取前面接口的某一个返回值做为请求参数&#xff0c;这时就可以使用关联。 如从A接口提取出a字段的值&#xff0c;供B接口的b字段使用。 一个接口的返回报文如下&#xff1a; {"retCode": "0&quo…

SwiftUI 集合视图(Grid)拖放交换 Cell 的极简实现

概览 自从 SwiftUI 横空出世那天起&#xff0c;小伙伴们都感受到了它惊人的简单与便捷。而在本课中&#xff0c;我们将会用一个小“栗子”更直观的让大家体验到它无与伦比简洁的描述性特质&#xff1a; 如上图所示&#xff0c;我们在 SwiftUI 中实现了 Grid 中拖放交换 Cell 的…

基于SpringBoot + Layui的社区物业管理系统

项目介绍 社区物业管理系统是基于java编程语言&#xff0c;springboot框架&#xff0c;idea工具&#xff0c;mysql数据库进行开发&#xff0c;本系统分为业主和管理员两个角色&#xff0c;业主可以登陆系统&#xff0c;查看车位费用信息&#xff0c;查看物业费用信息&#xff0…

2个wordpress优化SEO主题模板

SEO优化wordpress主题 简洁的SEO优化wordpress主题&#xff0c;效果好不好&#xff0c;结果会告诉你&#xff0c;适合SEO公司使用的主题。 https://www.jianzhanpress.com/?p2804 SEO优化海外WordPress主题 简洁的SEO优化海外服务商WordPress主题&#xff0c;为中国制造202…

HTTP REST 方式调用WebService接口(wsdl)

一、WebService接口正常使用SOAP协议调用&#xff0c;测试时常采用SoapUI软件调用&#xff0c;具体如下&#xff1a; 二、由于目前主流web服务逐渐转换为RESTful的形式&#xff0c;且SOAP协议的实现也是基于HTTP协议&#xff0c;故存在通过HTTP调用WebService接口的可能 2.1 …