首页 > 解决方案 > 存在性能问题的选项卡内容

问题描述

我正在尝试使用 ngfor 和 ngif 制作三个标签。它实际上可以工作,但存在性能问题 查看代码

<mat-nav-list class="op-content">
  <h5>Listar Usuários</h5>
  <input matInput [(ngModel)]="searchText" placeholder="Filtrar por nome" class="filter-input">
  <mat-tab-group>

    <mat-tab label="Todos" [(ngModel)]="searchText" name="todos" ngDefaultControl>
      <ng-container *ngFor="let op of tboperadores | filter : searchText">
        <mat-list-item>
          <a matLine [routerLink]="['/operadores', op.id_operador]">
            <span class="badge badge-primary"> {{op.id_operador}}</span>
            Nome: {{ op.nome }} CPF: {{ op.identificacao }}</a>
        </mat-list-item>
      </ng-container>
    </mat-tab>

    <mat-tab label="Habilitados" [(ngModel)]="searchText" name="habilitado" ngDefaultControl>
      <ng-container *ngFor="let op of tboperadores | filter : searchText">
        <ng-container *ngIf="op.habilitado =='S'">
          <mat-list-item>
            <a matLine [routerLink]="['/operadores', op.id_operador]">
              <span class="badge badge-primary"> {{op.id_operador}}</span>
              Nome: {{ op.nome }} CPF: {{ op.identificacao }}</a>
          </mat-list-item>
        </ng-container>
      </ng-container>
    </mat-tab>

    <mat-tab label="Desabilitados" [(ngModel)]="searchText" name="desabilitado" ngDefaultControl>
      <ng-container *ngFor="let op of tboperadores | filter : searchText">
        <ng-container *ngIf="op.habilitado=='N'">
          <mat-list-item>
            <a matLine [routerLink]="['/operadores', op.id_operador]">
              <span class="badge badge-primary"> {{op.id_operador}}</span>
              Nome: {{ op.nome }} CPF: {{ op.identificacao }}</a>
          </mat-list-item>
        </ng-container>
      </ng-container>
    </mat-tab>
  </mat-tab-group>
</mat-nav-list>
<div class="loader" *ngIf="!subscription?.closed" #loading>
</div>

如您所见,每次打开新标签时,我都有一个 ngfor。我试图为整个页面只放一个,但我无法让它工作。

有人知道如何解决它吗?

编辑:

我的operador.component.ts

import { Component, OnInit, } from '@angular/core';
import { Operador } from './operador';
import { OperadorService } from './operador.service';
import { Subscription, Observable } from 'rxjs';


@Component({
  selector: 'app-operador',
  templateUrl: './operador.component.html',
  styleUrls: ['./operador.component.css']
})
//export class OperadorComponent implements OnInit, PipeTransform {
export class OperadorComponent implements OnInit {
  tboperadores: Operador[];
  checkedOperadors: Operador[];

  subscription: Subscription;
  mode = 'indeterminate';

  constructor(private operadorService: OperadorService) {
  }

  ngOnInit(): void {
    this.subscription = this.getOperadores();
  }

  getOperadores() {

    return this.operadorService.getOperadores()
      .subscribe(ob => {
        console.log(ob);
        this.tboperadores = ob;
      });

  }
}

而且,我的 filter.pipe.ts:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'filter'
})
export class FilterPipe implements PipeTransform {
  transform(items: any[], searchText: string): any[] {
    if(!items) return [];
    if(!searchText) return items;
searchText = searchText.toLowerCase();
return items.filter( it => {
      return it.nome.toLowerCase().includes(searchText);
    });
   }
}

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';
import { Operador } from './operador';

const httpOptions = {
  headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};

@Injectable({
  providedIn: 'root'
})
export class OperadorService {
  private operadoresUrl = '******';  // URL to web api
  constructor( 
    private http: HttpClient
  ) { }

  getOperadores (): Observable<Operador[]> {
    return this.http.get<Operador[]>(this.operadoresUrl)
  }

  getOperador(id_operador: number): Observable<Operador> {
    const url = `${this.operadoresUrl}/${id_operador}`;
    return this.http.get<Operador>(url);
  }

  addOperador (operador: Operador): Observable<Operador> {
    return this.http.post<Operador>(this.operadoresUrl, operador, httpOptions);
  }

  deleteOperador (operador: Operador | number): Observable<Operador> {
    const id_operador = typeof operador === 'number' ? operador : operador.id_operador;
    const url = `${this.operadoresUrl}/${id_operador}`;

    return this.http.delete<Operador>(url, httpOptions);
  }

  updateOperador (operador: Operador): Observable<any> {
    return this.http.put(this.operadoresUrl, operador, httpOptions);
  }
}

编辑2:

我编辑了这个方法来做过滤器:

  getOperadores(option): Observable<Operador[]> {
    if (option == 0) {
      return this.http.get<Operador[]>(this.operadoresUrl)
    } else if (option == 1) {
      return this.http.get<Operador[]>(this.operadoresUrl).pipe(
        map((reports: Operador[]) => reports.filter(p => p.habilitado === "S"))
      );
    } else {
      return this.http.get<Operador[]>(this.operadoresUrl).pipe(
        map((reports: Operador[]) => reports.filter(p => p.habilitado === "N"))
      );

    }
  }

并创建了这两个方法来在构造函数中调用:

  checkedOperadores() {

    return this.operadorService.getOperadores(1)   
    .subscribe(  ob  =>  {
       console.log(ob);
       this.checkedOperadors = ob;
      });

  }

  uncheckedOperadores() {

    return this.operadorService.getOperadores(2)   
    .subscribe(  ob  =>  {
       console.log(ob);
       this.uncheckedOperadors = ob;
      });

  }

但性能问题仍在继续......

标签: angulartypescriptngfor

解决方案


从文档中,您可以使用延迟加载来增强初始化阶段:

https://material.angular.io/components/tabs/overview#lazy-loading

延迟加载
默认情况下,选项卡内容是急切加载的。急切加载的选项卡将初始化子组件,但在激活选项卡之前不会将它们注入 DOM。

如果选项卡包含多个复杂的子组件或者选项卡的内容在初始化时依赖于 DOM 计算,建议延迟加载选项卡的内容。

通过在具有 matTabContent 属性的 ng-template 中声明正文,可以延迟加载选项卡内容。

如果你仍然有性能问题,你必须弄清楚如何在你的 for 循环中使用虚拟滚动。

更新
我不知道您的过滤器管道是如何实现的,但是您必须注意它是纯的还是不纯的。与https://angular.io/guide/pipes#appendix-no-filterpipe-or-orderbypipe相关,它可能会导致性能问题。

您也可以改进您的代码:

1 - 创建三个 get 方法,每个方法都habilitado类似于:

get habilitados() {
   return tboperadores.filter(op => op.habilitado === 'S')
}

然后在 ngFor 中使用它并使用 ngIf。

2 - 也许为下面的代码创建一个组件以减少代码行:

<mat-list-item>
   <a matLine [routerLink]="['/operadores', op.id_operador]">
      <span class="badge badge-primary"> {{op.id_operador}}</span>
        Nome: {{ op.nome }} CPF: {{ op.identificacao }}
   </a>
</mat-list-item>

推荐阅读