基于列表类开发的列表组件

2020/5/3 11:25:36

本文主要是介绍基于列表类开发的列表组件,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

主要实现的功能

​ 排序、分页、过滤、自定义操作列、列表中根据数据展示相应图标、跳转详情页

组件继承思想

​ 封装一个列表基类,派生类继承该类,复用基类的功能。

Constructor 构造函数

​ 如果派生类未声明构造函数,它将使用基类的构造函数。这意味着在基类构造函数注入的所有服务,子组件都能访问到。

生命周期方法不继承

​ 如果基类中包含生命周期钩子,如 ngOnInitngOnChanges 等,而在派生类没有定义相应的生命周期钩子,基类的生命周期钩子会被自动调用。如果需要在派生类触发ngOnInit,则需要在派生类上定义相应的生命周期钩子。

继承的方法和属性基于可访问性级别

​ 派生类不能访问私有方法和属性,仅继承公共方法和属性。

模板是不能被继承

​ 模板是不能被继承的 ,派生类需自定义模板,因此共享的 DOM 结构或行为需要单独处理。

元数据和装饰器不继承

装饰器和元数据(@Component@Directive@NgModule等),这些元数据和装饰器不会被派生类继承,但是有一个例外,@Input@Output装饰器会传递给派生类

依赖注入

派生类必须通过调用super注入基类的参数

实现过程

application列表组件和基类ResourceListBaseResourceListWithStatuses 关系

application列表组件主要继承父类ResourceListWithStatuses,通过重写ResourceListWithStatuses的方法,自定义模板,来复用父类的功能属性。

组件定义

自定义模板
@Component({
  selector: 'sym-application-list',
  templateUrl: './application.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
复制代码
继承父类

通过expends继承父类

重写父类方法

通过继承基类ResourceListWithStatuses,可以复用其基本的功能属性,同时可以定义属性和方法扩展列表组件的功能,实现这个列表组件主要的是如果调用组件方法发起请求,获取到数据

  • 重写getResourceObservable 方法,该方法主要是返回一个Observable,进行异步编程。

    在这个方法里,可以请求多个api,使用Observable.forkJoin,可以合并多个Observable,返回一个Observable。

  • 结合sym-select 组件搜索

sym-select组件的namespace下拉列表的数据nsList是异步获取的,如果是选择是的namespace是ALL,那么列表组件要获取到nsList,然后对每个nsList里的namespace进行全部请求。如果选择的是某个namesapce,那么就传入namespace的值,进行单个请求

这里也是比较疑惑的地方,之前想通过@Input传入属性的方式,来把搜索组件的数据传递给applicaiton列表组件sym-application-list

但是尝试之后,发现在页面初始化的时候,通过@Input的属性传入的nsList为空的。如果传入的属性是同步获取的,则可以传递到application列表组件中

最后获取搜索参数的方式,采取服务依赖注入的方式来获取。

  • 通过重写map 方法,在自定义表格的数据,返回所需表格的数据。
ngOnInit() {
    this.data_.sortingDataAccessor = (item, property) => {
      switch (property) {
        case 'name': return item.objectMeta.name;
        case 'creationTimestamp': return item.status.creationTimestamp;
        case 'namespace': return item.objectMeta.namespace;
        default: return item[property];
      }
    };
  }

  getResourceObservable(params?: HttpParams): Observable<ApplicationList> {
    const res = this.localtionService_.onNamespaceUpdate.subscribe(() => {
      this.namespace = this.localtionService_.current().namespace;
      this.nsList = this.localtionService_.current().namespaceList;
    });
    const data: any = {
      items: [],
      listMeta: {
        totalItems: 0
      }
    };
    if (this.namespace === 'ALL') {
      const list = this.nsList.slice(1);
      const observableList = list.map((ns: any) => {
        return this.application_.get(this.endpoint, undefined, ns.name);
      });
      if (observableList && observableList.length === 0) {
        return new Observable((observer) => {
          observer.next(data);
        });
      }
      return new Observable((observer) => {
        Observable.forkJoin(observableList).subscribe((res: any) => {
          res.map((item: any, index: number) => {
            item.items = item.items.map((v: any) => {
              v.objectMeta.namespace = list[index].name;
              return v;
            });
            data.items = data.items.concat(item.items);
            data.listMeta.totalItems += item.listMeta.totalItems;
          });
          observer.next(data);
        });
      });
    } else if (this.namespace !== undefined) {
      return this.application_.get(this.endpoint, undefined, this.namespace, params);
    }
    return new Observable((observer) => {
      observer.next(data);
    });
  }

  map(applicationList: ApplicationList): Application[] {
    if (this.namespace !== 'ALL') {
      applicationList.items = applicationList.items.map((v: any) => {
        v.objectMeta.namespace = this.namespace;
        return v;
      });
    }
    console.log('applicationList', applicationList);
    return applicationList.items;
  }

  isInErrorState(resource: Application): boolean {
    return resource.status ? (resource.status.replicas && resource.status.replicas !== resource.status.availableReplicas ?
       true : false) : false;
  }

  isInSuccessState(resource: Application): boolean {
    return resource.status ? (resource.status.replicas && resource.status.replicas === resource.status.availableReplicas ?
       true : false) : false;
  }

  protected getDisplayColumns(): string[] {
    return ['statusicon', 'name', 'namespace', 'labels', 'replicas', 'creationTimestamp'];
  }
复制代码

组件使用

<sym-application-list #applicationList></sym-application-list>
复制代码

初始化时,调用getList请求方法

this.applicationList.getList();
复制代码

公共组件的巧妙之处

actionColumn 操作列可以自定义

在基类中已有声明注册操作列的方法,在application列表组件继承该方法,在构造函数中,注册操作列,MenuComponent是引入的组件

this.registerActionColumn<MenuComponent>('menu', MenuComponent);
复制代码
过滤功能

这里的Pods列表组件也是继承了ResourceListWithStatuses

继承的组件都会继承过滤功能,因为继承的组件的模板是自定义的,可以在模板上引入过滤的组件

<kd-card-list-filter></kd-card-list-filter>
复制代码

基类中以判断是否有过滤组件,并订阅过滤组件的方法触发列表过滤

ngAfterViewInit(): void {
    this.data_.sort = this.matSort_;
    this.data_.paginator = this.matPaginator_;

    if (this.cardFilter_) {
      // 表格搜索
      this.cardFilter_.filterEvent.subscribe(() => {
        const filterValue = this.cardFilter_.query;
        this.data_.filter = filterValue.trim().toLowerCase();
      });
    }
  }
复制代码

最后

​ 通过继承一些列表组件或者基类,可以大大地提升组件功能的复用率,并且能够提高开发效率。在一些业务场景中,我们总会面临着,多处一样的代码,如果有变动,就要全部更改,这样不利于代码的简洁,而且代码逻辑相对单一。由此我们要学会封装一些常用性的组件,来达到代码的复用率,加强代码的健壮性。

部分代码



这篇关于基于列表类开发的列表组件的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程