首页 > 解决方案 > 如何在 Angular 8 中制作相同的材质 sidenav 行为?

问题描述

当我使用sidenav组件加载页面时,左侧的菜单已关闭。如何使菜单默认打开,只有在减小窗口宽度后,才出现汉堡按钮,菜单本身折叠?我想做同样的事情https://material.angular.io/components/categories

我使用该命令创建新组件:

ng generate @angular/material:nav <component-name>

https://material.angular.io/guide/schematics

导航.component.html

<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="/about">About</a>
      <a mat-list-item href="/contact">Contact</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>NavApp</span>
    </mat-toolbar>
    <router-outlet></router-outlet>
    <!-- Add Content Here -->
  </mat-sidenav-content>
</mat-sidenav-container>

导航.component.ts

import { Component } from '@angular/core';
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
import { Observable } from 'rxjs';
import { map, share } from 'rxjs/operators';

@Component({
  selector: 'app-navigation',
  templateUrl: './navigation.component.html',
  styleUrls: ['./navigation.component.scss']
})
export class NavigationComponent {

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

  constructor(private breakpointObserver: BreakpointObserver) {}

}

当我尝试更改 [opened]="true" 左侧菜单已打开,但 this.breakpointObserver.observe(Breakpoints.Handset) 没有事件绑定并且如果我调整窗口左侧菜单未关闭

标签: angulartypescriptmaterial-design

解决方案


我相信您遇到的问题是,在您的组件中,您使用运算符在 HTML 模板中的四个订阅者(异步管道)之间share()共享 observable 。this.breakpointObserver.observe()

这意味着这个 observable 将在它第一次被订阅(在<mat-sidenav>元素中)时发出;此发射将被共享,但由于您的<button>元素尚未创建,发射太早并且<button>永远不会收到它。这意味着*ngIfon 按钮将在第一次加载时评估为 false,即使isHandset$实际上已经发出 true,因此您不会在移动视图上看到菜单按钮。

为了解决这个问题,您可以使用shareReplay()运算符而不是share(),它将重播来自this.breakpointObserver.observe()所有新订阅者(例如 中的订阅者<button>)的发射,即使它们是在发射之后创建的。

导航.component.ts

import { Component } from '@angular/core';
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
import { Observable } from 'rxjs';
import { map, shareReplay } from 'rxjs/operators';

@Component({
    selector: 'app-navigation',
    templateUrl: './navigation.component.html',
    styleUrls: ['./navigation.component.scss']
})
export class NavigationComponent {
    isHandset$: Observable<boolean> = this.breakpointObserver.observe(Breakpoints.Handset)
        .pipe(
            map(result => result.matches),
            shareReplay(1),
        );

    constructor(private breakpointObserver: BreakpointObserver) { }
}

推荐阅读