如何减少模板上的异步管道订阅数

How to reduce the number async pipe subscriptions on template

我有这个组件StackBliz

模板:

<mat-sidenav-container class="sidenav-container">
  <mat-sidenav #drawer class="sidenav" fixedInViewport
      [attr.role]="(isHandset$ | async) ? 'dialog' : 'navigation'"
      [mode]="(isHandset$ | async) ? 'over' : 'side'"
      [opened]="(isHandset$ | async) === false">
    <mat-toolbar>Menu</mat-toolbar>
    <mat-nav-list>
      <a mat-list-item href="#">Link 1</a>
      <a mat-list-item href="#">Link 2</a>
      <a mat-list-item href="#">Link 3</a>
    </mat-nav-list>
  </mat-sidenav>
  <mat-sidenav-content>
    <mat-toolbar color="primary">
      <button
        type="button"
        aria-label="Toggle sidenav"
        mat-icon-button
        (click)="drawer.toggle()"
        *ngIf="isHandset$ | async">
        <mat-icon aria-label="Side nav toggle icon">menu</mat-icon>
      </button>
      <span>dashboard-app</span>
    </mat-toolbar>
  </mat-sidenav-content>
</mat-sidenav-container>

Class:

export class NavigationComponent {

  isHandset$: Observable<boolean> = this.breakpointObserver.observe(Breakpoints.Handset)
    .pipe(
      map(result => result.matches),
      shareReplay()
    );

  constructor(private breakpointObserver: BreakpointObserver) {}

}

我想减少页面上的订阅数量。

我尝试将内容包装到 ng-container 中,但这没有用。

首先,我在 [opened]="isHandset === false" 中的模板中遇到错误,其次,ng-container 破坏了视图,所以即使我按原样离开,[opened]="(isHandset$ | async) === false" 也没有任何问题显示

<mat-sidenav-container class="sidenav-container">
    <ng-container *ngIf="isHandset$ | async as isHadset">
      <mat-sidenav #drawer class="sidenav" fixedInViewport
           [attr.role]="isHadset ? 'dialog' : 'navigation'"
           [mode]="isHadset ? 'over' : 'side'"
           [opened]="isHadset === false"> //got an error here saying this condition is always false because isHadset is always 'true'
    ...
           *ngIf="isHadset"
    ...
    
    
      </mat-sidenav-content>
    <ng-container>
</mat-sidenav-container>

关于如何解决我上面描述的所有两个问题有什么想法吗?

使用带有 boolean 发射的 *ngIf 并不理想,因为如果值为 false,它不会呈现元素。但是我看到最初你的发射是一个物体。由于对象是真实的,您可以忽略到布尔值的映射并直接将其与 *ngIf.

一起使用

我还建议将整个容器包裹在 <ng-container> 中以保留 DOM。

尝试以下方法

控制器 (*.ts)

import { BreakpointObserver, Breakpoints, BreakpointState } from '@angular/cdk/layout';
...

export class NavigationComponent {
  isHandset$: Observable<BreakpointState>;

  constructor(private breakpointObserver: BreakpointObserver) {
    this.isHandset$ = this.breakpointObserver.observe(Breakpoints.Handset);
  }
}

模板(*.html)

<ng-container *ngIf="(isHandset$ | async) as result">
  <mat-sidenav-container class="sidenav-container">
    <mat-sidenav 
      #drawer 
      class="sidenav" 
      fixedInViewport 
      [attr.role]="(result.matches) ? 'dialog' : 'navigation'"
      [mode]="(result.matches) ? 'over' : 'side'" 
      [opened]="!result.matches"
    >
      <mat-toolbar>Menu</mat-toolbar>
      <mat-nav-list>
        <a mat-list-item href="#">Link 1</a>
        <a mat-list-item href="#">Link 2</a>
        <a mat-list-item href="#">Link 3</a>
      </mat-nav-list>
    </mat-sidenav>
    <mat-sidenav-content>
      <mat-toolbar color="primary">
        <button
          type="button"
          aria-label="Toggle sidenav"
          mat-icon-button
          (click)="drawer.toggle()"
          *ngIf="result.matches"
        >
          <mat-icon aria-label="Side nav toggle icon">menu</mat-icon>
        </button>
        <span>dashboard-app</span>
      </mat-toolbar>
    </mat-sidenav-content>
  </mat-sidenav-container>
</ng-container>

我修改了你的Stackblitz