无需switch语句复用Angular组件加载不同数据及Angular5组件复用问题
优雅复用
citySelect组件的方案(无需switch语句) 嘿,我来给你捋捋怎么在Angular 5里灵活复用这个城市选择组件,完全不用switch来硬编码不同的数据加载逻辑~ 核心思路是让组件不关心具体加载什么数据,而是把数据加载的逻辑交给外部,下面给你几个实用的方案:
方案1:通过@Input()传入数据加载函数
这是最直接的方式,组件只负责UI和联动逻辑,数据加载的具体实现由父组件传入。
1.1 修改citySelect.component.ts
定义一个输入属性,接收返回Observable的函数,组件内部调用这个函数获取数据:
import { Component, Input, OnInit } from '@angular/core'; import { Observable } from 'rxjs/Observable'; @Component({ selector: 'app-city-select', templateUrl: './city-select.component.html' }) export class CitySelectComponent implements OnInit { // 外部传入数据加载函数,支持带参数(比如联动场景) @Input() loadDataFn: (params?: any) => Observable<any[]>; dataList: any[] = []; ngOnInit() { if (this.loadDataFn) { // 如果是联动场景,比如选完国家加载省份,这里可以在选择事件里调用并传参 this.loadDataFn().subscribe(data => { this.dataList = data; // 后续的国家/省份/城市联动逻辑正常写就行 }); } } // 示例:联动场景下的调用 onCountrySelected(countryId: string) { this.loadDataFn(countryId).subscribe(provinces => { this.provinces = provinces; }); } }
1.2 父组件(比如personForm.component)使用
直接把对应的数据加载逻辑传入组件:
<!-- 加载城市人员数据 --> <app-city-select [loadDataFn]="loadCityPersons"></app-city-select>
import { Component } from '@angular/core'; import { DataService } from './data.service'; @Component({ selector: 'app-person-form', templateUrl: './person-form.component.html' }) export class PersonFormComponent { constructor(private dataService: DataService) {} // 封装数据服务的调用,传给子组件 loadCityPersons() { return this.dataService.getCityPersons(); } }
如果要复用组件加载其他数据(比如公司列表),只需要在另一个父组件里传入新的loadCompanyData函数就行,完全不用修改citySelect组件。
方案2:用抽象类+依赖注入实现策略模式
如果你的数据加载逻辑比较复杂,需要不同的服务实现,可以用这种方式,符合开闭原则。
2.1 定义抽象数据加载类
// data-loader.abstract.ts import { Observable } from 'rxjs/Observable'; export abstract class DataLoader { abstract loadData(params?: any): Observable<any[]>; }
2.2 实现具体的数据加载服务
比如针对城市人员数据:
// city-person-loader.service.ts import { Injectable } from '@angular/core'; import { DataLoader } from './data-loader.abstract'; import { DataService } from './data.service'; @Injectable() export class CityPersonLoader implements DataLoader { constructor(private dataService: DataService) {} loadData(): Observable<any[]> { return this.dataService.getCityPersons(); } }
2.3 修改citySelect组件注入抽象类
import { Component, OnInit, Inject } from '@angular/core'; import { DataLoader } from './data-loader.abstract'; @Component({ selector: 'app-city-select', templateUrl: './city-select.component.html' }) export class CitySelectComponent implements OnInit { dataList: any[] = []; // 注入抽象类,不依赖具体实现 constructor(@Inject(DataLoader) private dataLoader: DataLoader) {} ngOnInit() { this.dataLoader.loadData().subscribe(data => { this.dataList = data; }); } }
2.4 在模块中提供具体实现
比如在人员表单模块里提供城市人员加载服务:
// person-form.module.ts import { NgModule } from '@angular/core'; import { CitySelectComponent } from './city-select.component'; import { DataLoader } from './data-loader.abstract'; import { CityPersonLoader } from './city-person-loader.service'; @NgModule({ declarations: [CitySelectComponent], providers: [ { provide: DataLoader, useClass: CityPersonLoader } ], exports: [CitySelectComponent] }) export class PersonFormModule {}
如果要在其他模块复用组件,只需要提供另一个DataLoader的实现(比如CompanyLoader)就行,组件内部完全不用改。
方案3:针对三级联动的专属配置
如果你的组件核心是国家-省份-城市的三级联动,可以给每个级别单独传入加载函数:
@Component({ selector: 'app-city-select', templateUrl: './city-select.component.html' }) export class CitySelectComponent implements OnInit { @Input() loadCountries: () => Observable<any[]>; @Input() loadProvinces: (countryId: string) => Observable<any[]>; @Input() loadCities: (provinceId: string) => Observable<any[]>; countries: any[] = []; provinces: any[] = []; cities: any[] = []; ngOnInit() { this.loadCountries().subscribe(data => this.countries = data); } onCountryChange(countryId: string) { this.loadProvinces(countryId).subscribe(data => { this.provinces = data; this.cities = []; }); } onProvinceChange(provinceId: string) { this.loadCities(provinceId).subscribe(data => this.cities = data); } }
父组件使用时传入对应级别的加载逻辑:
<app-city-select [loadCountries]="loadCountries" [loadProvinces]="loadProvinces" [loadCities]="loadCities" ></app-city-select>
这种方式完全适配三级联动的场景,复用的时候只需要替换三个加载函数,比如改成行业-分类-产品的联动。
内容的提问来源于stack exchange,提问作者dfmetro
相关产品推荐
相关产品推荐

