Angular 4でのリアルタイムのウィンドウサイズ変更の検出


118

私はレスポンシブなナビゲーションバーを構築しようとしており、メディアクエリを使用したくないので*ngIF、ウィンドウサイズを基準として使用するつもりです。しかし、Angular 4のウィンドウサイズの検出に関する方法やドキュメントが見つからないため、問題に直面しています。JavaScriptメソッドも試しましたが、サポートされていません。

私は以下も試しました:

constructor(platform: Platform) {
    platform.ready().then((readySource) => {
        console.log('Width: ' + platform.width());
        console.log('Height: ' + platform.height());
    });
}

...これはイオンで使用されました。

そしてscreen.availHeight、まだ成功していません。


1
platformについて?これはIonicについてですか?
ギュンターZöchbauer

@GünterZöchbauerプラットフォームは角張っており、私が試したコードに言及したいだけです。
Oommen

1
PlatformIonicサービスです。それで、それはIonicプロジェクトだと思いますか?
robbannn 2017


@BlackBeard Angular 2と4の違いが原因で、重複しているとは思いません。
tehlivi 2018

回答:


260

initで取得するには

public innerWidth: any;
ngOnInit() {
    this.innerWidth = window.innerWidth;
}

サイズ変更時に更新したい場合:

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

2
this.innerWidth = event.target.innerWidth; ...おそらくより効率的で、同じ結果が生成されます
danday74

2
また、lodashを使用している場合は、コンストラクターでこれを推奨します... this.onResize = debounce(this.onResize、150、{leading:false、trailing:true})... onResizeメソッドが頻繁に呼び出されないようにします.. 。する必要があります...インポート{デバウンス}から 'lodash'
danday74

私はngAfterViewInitライフフックメソッドの代わりに ngOnInit ライフフックメソッドを使用することをお
勧めします

39

特定のブレークポイントに反応したい場合(たとえば、幅が768px未満の場合に何かを実行する場合)、BreakpointObserverを使用することもできます。

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

{ ... }

const isSmallScreen = breakpointObserver.isMatched('(max-width: 599px)');

または、そのブレークポイントの変更をリッスンします。

breakpointObserver.observe([
  '(max-width: 768px)'
    ]).subscribe(result => {
      if (result.matches) {
        doSomething();
      } else {
        // if necessary:
        doSomethingElse();
      }
    });

オブザーバーが基準に一致する場合にのみアクションを実行したい場合は、サブスクライブ内に追加する必要があります。if (result.matches)それ以外の場合は、そうでない場合でも呼び出します
karoluS

1
@karoluS:もちろんです。私はそれを明確にするために私の答えを編集しました。ありがとうございました。
Jeremy Benks、

これcdkはangularの特定のバージョンにピア依存性があるようです。最新の7のように。とにかく私はこれを古いバージョン(質問のように角度4)に使用できますか?
LeOn-Han Li

@レオン・リー:私は実際には角度7を使用しています。ただし、私が知る限り、角度4でもcdkを使用できます。このブログ投稿によると cdk 2.xが必要です。私の知る限り、これは手動でインストールし、次のようにバージョンを指定する必要があります
。npm

@JeremyBenks Y、4.2.6具体的にはngを使用しています。cdk 2.xバージョンを見つけることができません。4.1.xと4.3.xのみです。まあありがとう!
LeOn-Han Li

9

コンポーネントを簡単にテストできるようにするには、グローバルウィンドウオブジェクトをAngular Serviceでラップする必要があります。

import { Injectable } from '@angular/core';

@Injectable()
export class WindowService {

  get windowRef() {
    return window;
  }

}

その後、他のサービスと同じように注入できます。

constructor(
    private windowService: WindowService
) { }

そして消費...

  ngOnInit() {
      const width= this.windowService.windowRef.innerWidth;
  }

2
すでに手元にあるサービスを正確に行うためのサービスの要点がわかりません。window.innerWidth。
ロドリゴ

1
まず、DIはAngularの方法であり、コンポーネント/ディレクティブの依存関係をより明確にします。ただし、ここで説明する主なポイントは、サービスを使用するコードをテストしやすくすることです。このアプローチを使用すると、サービスを使用するコンポーネント用に作成された任意のテストでWindowServiceを模倣できます。
Kildareflare

9

Platform width()およびのドキュメントにheight()は、これらのメソッドがそれぞれwindow.innerWidthとを使用することが記載されていwindow.innerHeightます。ただし、これらのメソッドを使用することをお勧めします。これは、ディメンションがキャッシュされた値であり、複数の高価なDOM読み取りの可能性を減らすためです。

import { Platform } from 'ionic-angular';

...
private width:number;
private height:number;

constructor(private platform: Platform){
    platform.ready().then(() => {
        this.width = platform.width();
        this.height = platform.height();
    });
}

の取得widthはどのようにwindow関係していDOMますか?論理的には、domツリーがどのように見えるかに依存するべきではありません。
Shahryar Saljoughi

6

これは私が使っているサービスの例です。

に登録するscreenWidth$か、screenWidth$.value

mediaBreakpoint$(またはmediaBreakpoint$.value)も同じです

import {
  Injectable,
  OnDestroy,
} from '@angular/core';
import {
  Subject,
  BehaviorSubject,
  fromEvent,
} from 'rxjs';
import {
  takeUntil,
  debounceTime,
} from 'rxjs/operators';

@Injectable()
export class ResponsiveService implements OnDestroy {
  private _unsubscriber$: Subject<any> = new Subject();
  public screenWidth$: BehaviorSubject<number> = new BehaviorSubject(null);
  public mediaBreakpoint$: BehaviorSubject<string> = new BehaviorSubject(null);

  constructor() {}

  init() {
    this._setScreenWidth(window.innerWidth);
    this._setMediaBreakpoint(window.innerWidth);
    fromEvent(window, 'resize')
      .pipe(
        debounceTime(1000),
        takeUntil(this._unsubscriber$)
      ).subscribe((evt: any) => {
        this._setScreenWidth(evt.target.innerWidth);
        this._setMediaBreakpoint(evt.target.innerWidth);
      });
  }

  ngOnDestroy() {
    this._unsubscriber$.next();
    this._unsubscriber$.complete();
  }

  private _setScreenWidth(width: number): void {
    this.screenWidth$.next(width);
  }

  private _setMediaBreakpoint(width: number): void {
    if (width < 576) {
      this.mediaBreakpoint$.next('xs');
    } else if (width >= 576 && width < 768) {
      this.mediaBreakpoint$.next('sm');
    } else if (width >= 768 && width < 992) {
      this.mediaBreakpoint$.next('md');
    } else if (width >= 992 && width < 1200) {
      this.mediaBreakpoint$.next('lg');
    } else if (width >= 1200 && width < 1600) {
      this.mediaBreakpoint$.next('xl');
    } else {
      this.mediaBreakpoint$.next('xxl');
    }
  }

}

これが誰かを助けることを願っています


私の好きな答え!this.init()をコンストラクターに追加して機能させるようにしてください。
ベン


3
@HostListener("window:resize", [])
public onResize() {
  this.detectScreenSize();
}

public ngAfterViewInit() {
    this.detectScreenSize();
}

private detectScreenSize() {
    const height = window.innerHeight;
    const width = window.innerWidth;
}

3
なぜこれが適切な解決策になるのかを常に説明する
thedp

3

答えは非常に簡単です。以下のコードを書きます

import { Component, OnInit, OnDestroy, Input } from "@angular/core";
// Import this, and write at the top of your .ts file
import { HostListener } from "@angular/core";

@Component({
 selector: "app-login",
 templateUrl: './login.component.html',
 styleUrls: ['./login.component.css']
})

export class LoginComponent implements OnInit, OnDestroy {
// Declare height and width variables
scrHeight:any;
scrWidth:any;

@HostListener('window:resize', ['$event'])
getScreenSize(event?) {
      this.scrHeight = window.innerHeight;
      this.scrWidth = window.innerWidth;
      console.log(this.scrHeight, this.scrWidth);
}

// Constructor
constructor() {
    this.getScreenSize();
}
}

1

このシナリオでは、typescript getterメソッドを使用できます。このような

public get width() {
  return window.innerWidth;
}

そして、それを次のようなテンプレートで使用します:

<section [ngClass]="{ 'desktop-view': width >= 768, 'mobile-view': width < 768 
}"></section>

ウィンドウのサイズ変更/を確認するためのイベントハンドラーは必要ありません。このメソッドは、毎回自動的にサイズを確認します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.