Material2:显示/隐藏md-sidenav取决于媒体

时间:2016-10-29 16:10:40

标签: angular angular2-material

我想在大屏幕上打开 md-sidenav 并在移动设备上关闭它。在我的应用程序中执行此操作的正确方法是什么?

是否有可能在angular2组件内查询媒体?

5 个答案:

答案 0 :(得分:8)

在组件类中,我定义了对sidenav的引用并监听窗口调整大小事件。取决于window.inner,您可以构建逻辑。

  @ViewChild('sidenav') sidenav: MdSidenav

  @HostListener('window:resize', ['$event'])
  onResize(event) {
    this.configureSideNav()
  }

  configureSideNav() {
    this.smallScreen = window.innerWidth < 501 ? true : false
    if (!this.smallScreen) {
      this.sidenav.mode = "side"
      this.sidenav.opened = true
    } else {
      this.sidenav.mode = 'over'
      this.sidenav.opened = false
    }
  }

答案 1 :(得分:3)

我刚刚找到了一个更好的方法来听取Angular中的屏幕更改:https://github.com/angular/flex-layout/wiki/ObservableMedia

它是一个 Angular Flex Layout 模块,它将mediaQuery激活通知作为可观察对象提供。所以不需要手动创建resize监听器。

此外,MediaChange类提供了方便的别名(lgmdxs等),可用于决定屏幕大小特定的表达式。< / p>

查看维基页面上的示例。

答案 2 :(得分:2)

我们有一个仪表板组件,它是整个应用程序的布局容器。

dashboard.html:

<md-sidenav-layout class="sidenav-layout">

  <bv-toolbar (toggleSidenav)="start.toggle()" [screenWidth]="screenWidth"></bv-toolbar>
  <md-sidenav #start [opened]="screenWidth > 1000" [mode]="(screenWidth > 1000) ? 'side' : 'start'">
    <bv-sidenav-content  [user]="user$ | async" [screenWidth]="screenWidth" (navClose)="start.toggle()"></bv-sidenav-content>
  </md-sidenav>

  <div class="sidenav-content"></div>
</md-sidenav-layout>

请注意我们如何使用[screenWidth]="screenWidth"通过模板将screenWidth值从仪表板发送到工具栏(和sidenav)组件。

dashboard.ts:

...
export class DashboardComponent {
  screenWidth: number;
...
constructor (private cdr: ChangeDetectorRef, private store: Store<fromRoot.State> ) {

  var that = this;
  // set screenWidth on page load
  that.screenWidth = window.innerWidth;
  window.onresize = () => {
    // set screenWidth on screen size change
    that.screenWidth = window.innerWidth;
    that.cdr.detectChanges();
  }
}

现在我们的仪表板上设置了screenWidth,并通过模板发送到其他组件,我们需要使用@Input()在子组件的脚本中接收它,然后它就可用了在子组件的模板中也是如此。

toolbar.ts:

...
export class ToolbarComponent {
  @Output() toggleSidenav = new EventEmitter();
  @Input() screenWidth : number;
}

这将允许工具栏的模板访问仪表板中先前定义的screenWidth变量,并在每次更改时获取更新(因此您可以在仪表板中设置一次逻辑并继承整个应用程序的价值无处不在。

toolbar.html:

<md-toolbar color="primary">
  <button md-icon-button
          (click)="toggleSidenav.emit()"
          [ngClass]="{'h-hide': screenWidth > 1000}">
      <md-icon>menu</md-icon>
  </button>
</md-toolbar>

答案 3 :(得分:1)

我从另一篇文章中找到了解决方案:rxjs/behaviorsubject

您可以从BehaviorSubject.window获取宽度的值。我正在使用它来改变sidenav模式在“side”和“over”之间。

windows.service.ts:

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';

@Injectable()
export class WindowService {
    public window = new BehaviorSubject(null);

    public width: Observable<number>;

    constructor() {
        let windowSize = new BehaviorSubject(getWindowSize());

        this.width = (windowSize.pluck('width') as Observable<number>).distinctUntilChanged();

        Observable.fromEvent(window, 'resize')
            .map(getWindowSize)
            .subscribe(windowSize);
    }


}

function getWindowSize() {
    return {
        width: window.innerWidth
    };
}

component.ts:

ngOnInit() {
    // Change sideNav mode between over and side depending on size of window
    this.windowService.width.subscribe((width) => {
      if (width) {
        console.log(width);
        if (width < 600) {
          this.sideNavMode = "over"
        } else {
          this.sideNavMode = "side"
        }
      }
    });
}

答案 4 :(得分:1)

我今天在工作场所解决了同样的问题。我基本上使用@AndyGrey指出的相同方法完成了它。我认为代码示例可能对某人有帮助。

sidenav-layout.component.ts

    import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
    import { ObservableMedia, MediaChange } from '@angular/flex-layout';
    import { MdSidenav } from '@angular/material';
    import { Subscription } from 'rxjs/Subscription';

    @Component({
      selector: 'sidenav-layout',
      templateUrl: './sidenav-layout.component.html',
      styleUrls: [ './sidenav-layout.component.scss' ]
    })

    export class SidenavLayoutComponent implements OnInit, OnDestroy {

      @ViewChild('sidenav') sidenav: MdSidenav;

      private _mediaSubscription: Subscription;
      sidenavOpen = true;
      isMobile = false;

      constructor(private media: ObservableMedia) {}

      ngOnInit() {
        this._mediaSubscription = this.media.asObservable().subscribe((change: 
     MediaChange) => {
      this.isMobile = (change.mqAlias === 'xs') || (change.mqAlias === 'sm');
      this.sidenavOpen = !this.isMobile;
    });
  }

  onLinkClick() {
    if (this.isMobile) {
      this.sidenav.toggle();
    }
  }

  ngOnDestroy() {
    this._mediaSubscription.unsubscribe();
  }
}

sidenav-layout.component.html

 <md-sidenav #sidenav mode="side" opened={{sidenavOpen}}>

应将onLinkClick()方法添加到所有列表项中。因此,只要在移动视图中单击链接,就会切换(隐藏)sidenav。

最后不要忘记取消订阅mediaSubscription Observable:)