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

主要实现的功能

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

组件继承思想

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

Constructor 构造函数

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

生命周期方法不继承

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

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

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

模板是不能被继承

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

元数据和装饰器不继承

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

依赖注入

派生类必须经过调用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();
      });
    }
  }
复制代码

最后

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

部分代码

相关文章
相关标签/搜索