Angular中无关联独立组件间如何调用方法共享搜索数据
独立Angular组件共享搜索数据实现方案
两个无关联独立组件要复用同一份搜索逻辑和返回数据,对初学者最友好、维护成本最低的实现方式是共享服务+RxJS BehaviorSubject,不需要处理复杂的组件层级传值,按以下步骤落地即可:
第一步:抽离公共逻辑到共享服务
不要在两个组件里重复写接口调用代码,先新建一个共享服务,专门存放搜索相关的逻辑和数据。你可以在annotation功能的公共目录下创建annotation-shared.service.ts,代码如下:
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { BehaviorSubject } from 'rxjs'; // 全应用单例注入,不用重复在模块providers里声明 @Injectable({ providedIn: 'root' }) export class AnnotationSharedService { // 存储最新的搜索结果,初始值为空数组 private searchResultSource = new BehaviorSubject<any[]>([]); // 对外暴露可订阅的数据流,所有组件都能拿到最新数据 public searchResult$ = this.searchResultSource.asObservable(); constructor(private http: HttpClient) {} // 把原来写在pm-admin-list组件里的searchDetails逻辑挪到这里 searchDetails(keyword: string) { // 替换成你实际的接口地址和请求参数 this.http.get('你的实际业务接口地址', { params: { searchKey: keyword } }) .subscribe((res: any[]) => { // 接口返回数据后推送新值,所有订阅的组件自动收到更新 this.searchResultSource.next(res); }) } }
注意:使用HttpClient前要确保项目的根模块或者对应功能模块已经导入
HttpClientModule,否则请求会报错。
第二步:改造原有pm-admin-list组件
把组件内独立写的接口请求逻辑替换成调用共享服务,同时订阅服务的搜索结果数据流,代码改动如下:
pm-admin-list.component.ts
import { Component, OnInit } from '@angular/core'; import { AnnotationSharedService } from '替换成你服务的实际存放路径/annotation-shared.service'; @Component({ selector: 'app-pm-admin-list', templateUrl: './pm-admin-list.component.html' }) export class PmAdminListComponent implements OnInit { search = ''; items: any[] = []; // 注入共享服务 constructor(private annotationSharedService: AnnotationSharedService) {} ngOnInit() { // 组件初始化时订阅搜索结果,数据变化自动同步到本地items变量 this.annotationSharedService.searchResult$.subscribe(result => { this.items = result; }) } searchDetails() { // 直接调用服务的搜索方法,传入输入框的关键词 this.annotationSharedService.searchDetails(this.search); } }
pm-admin-list.component.html
顺便修复你原有代码里的几个语法错误:placeolder拼写错误、status插值缺少左大括号、li标签闭合错误,修正后代码:
<div> <input placeholder="search here" [(ngModel)]="search" (keyup.enter)="searchDetails()"> <img src="assets/imgs/search-icon"> </div> <ul *ngFor="let data of items"> <li>{{data.name}}</li> <li>{{data.status}}</li> <li>{{data.lang}}</li> </ul>
注意:使用
[(ngModel)]双向绑定前,要确保对应功能模块已经导入FormsModule,否则绑定不生效。
第三步:在annotation-process-list组件中复用数据
这个组件不需要重复写接口请求逻辑,只要订阅共享服务的数据流即可;如果需要在这个组件里也放搜索框,直接调用同一个搜索方法,两边搜索的结果会自动同步。
annotation-process-list.component.ts 示例
import { Component, OnInit } from '@angular/core'; import { AnnotationSharedService } from '替换成你服务的实际存放路径/annotation-shared.service'; @Component({ selector: 'app-annotation-process-list', templateUrl: './annotation-process-list.component.html' }) export class AnnotationProcessListComponent implements OnInit { // 如果这个组件需要内置搜索框就声明search变量,不需要可以删掉 search = ''; processList: any[] = []; constructor(private annotationSharedService: AnnotationSharedService) {} ngOnInit() { // 和原有组件一样订阅数据,拿到结果直接渲染 this.annotationSharedService.searchResult$.subscribe(result => { this.processList = result; }) } // 如果这个组件需要搜索功能就加这个方法,不需要可以删掉 handleSearch() { this.annotationSharedService.searchDetails(this.search); } }
annotation-process-list.component.html 示例
<!-- 需要搜索框就放开下面的注释,不需要就只保留列表部分 --> <!-- <div> <input placeholder="搜索任务" [(ngModel)]="search" (keyup.enter)="handleSearch()"> </div> --> <ul *ngFor="let data of processList"> <li>{{data.name}}</li> <li>{{data.status}}</li> <li>{{data.lang}}</li> </ul>
初学者避坑提示
- 不要复制粘贴相同的接口请求代码到两个组件,后期改接口地址、传参规则要改两处,很容易漏改出bug
@Input/@Output传值只适用于有直接父子关系的组件,你现在两个独立组件用服务共享数据是最合理的方案- 服务的
@Injectable装饰器要保留providedIn: 'root'配置,保证整个应用用的是同一个服务实例,不会出现数据不同步的问题 - 简单场景下http请求的订阅会自动销毁,不用担心内存泄漏;等你熟悉Angular后可以改用
async管道直接在模板订阅,连ts里的subscribe逻辑都可以省掉
内容的提问来源于stack exchange,提问作者user1
相关产品推荐
相关产品推荐

