[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.pswp.cn/news/696908.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/696908.shtml
英文地址,請注明出處:http://en.pswp.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應…

idea打開項目白屏

解決方法&#xff1a; 右鍵“最大化” idea打開項目白板解決方案_idea打開白屏-CSDN博客 IDEA 2022 CPU占用100%的問題及解決方法_java_腳本之家

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…

【Nginx】Nginx配置反向代理 和 https

nginx.conf配置 進入linux /etc/nginx/ 打開nginx.conf 進行以下配置 http {include mime.types;default_type application/octet-stream;sendfile on;keepalive_timeout 65;server {#監聽443端口listen 443 ssl;#你的域名server_name huiblog.top;#ssl證書的pe…

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…

【es6】模版字面量/模版字符串,標簽函數/String.raw()靜態方法

模版字符串經常用&#xff0c;但是這個標簽函數的功能你肯定不知道&#xff0c;請看官網文檔 看完你需要知道 可以自定義標簽函數String.raw 的用法 唯一一個內置的模版字符串標簽函數第一個參數具有 raw 屬性的對象&#xff0c;值時一個類數組字符串對象模版字面量的緩存機制…

【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動態代理,…

算法提升——LeetCode第385場周賽總結

題目 統計前后綴下標對 I 給你一個下標從0開始的字符串數組words。 定義一個布爾函數isPrefixAndSuffix&#xff0c;它接受兩個字符串參數str1和str2&#xff1a; 當str1同時是str2的前綴&#xff08;prefix&#xff09;和后綴&#xff08;suffix&#xff09;時&#xff0c…

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

文章目錄 appium連接手機java代碼實現-第一版第二版-接入testng和隱式等待顯示等待 appium連接手機 準備工作 1、查看連接手機模擬器是否連接成功&#xff0c;獲取設備名稱 執行命令&#xff1a;adb devices 2、查看android內核版本號—>paltformVersion 執行命令&#xf…

MQL語言實現單元測試

文章目錄 一、單元測試是什么二、單元測試的過程三、為什么需要單元測試四、MQL測試代碼實現 一、單元測試是什么 單元測試是對軟件中最小可測單元&#xff08;如類或函數&#xff09;進行獨立驗證和檢查的過程。它是由開發工程師完成的&#xff0c;旨在確保每個單元的功能和邏…