Angular window resize event


232

ウィンドウのサイズ変更イベント(ロード時および動的)に基づいていくつかのタスクを実行したいと思います。

現在、私は次のように私のDOMを持っています:

<div id="Harbour">
    <div id="Port" (window:resize)="onResize($event)" >
        <router-outlet></router-outlet>
    </div>
</div>

イベントは正しく発生します

export class AppComponent {
   onResize(event) {
        console.log(event);
    }
}

このイベントオブジェクトから幅と高さを取得するにはどうすればよいですか?

ありがとう。


6
本当に問題ではありません。ウィンドウオブジェクトを見てください。あなたはそれがだ得ることができますinnerHeightし、innerWidthプロパティ...
Sasxa

1
@Sasxaは正解です。やらなければならないことはありませんconsole.log(event.target.innerWidth )
Pankaj Parkar '20

情報をありがとうSasxa / Pankaj-それが単なるjavascriptなのか、Typescriptなのか、Angularイベントなのかわからなかった。ここで私は非常に急な学習曲線を登っています。あなたの意見に感謝します。
DanAbdn 2016

回答:


527
<div (window:resize)="onResize($event)"
onResize(event) {
  event.target.innerWidth;
}

またはHostListenerデコレータを使用する:

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

サポートされている世界的な標的であるwindowdocumentbody

https://github.com/angular/angular/issues/13248がAngularで実装されるまで、他のいくつかの回答に示されているように、パフォーマンスのためにDOMイベントを強制的にサブスクライブし、RXJSを使用してイベントの量を減らす方が良いです。


15
使用する構文に関するドキュメントはありますか: window:resize
クレメント

3
丁度。、、およびgithub.com/angular/angular/blob/…を使用できますdocumentwindowbody
GünterZöchbauer16年

5
完璧な答えです。@ HostListenerの方がきれいな方法だと思いますが、最初にHostListenerをインポートしてくださいimport { Component, OnInit, HostListener } from '@angular/core';
Gaurav Sharma

4
クイックヒント:最初のロードでもトリガーしたい場合は、@ angular / coreからngAfterViewInitを実装します。angular.io/api/core/AfterViewInit
Zymotik

7
ただし、HostListenerがdebounceTimeでどのように動作するかを知りたい場合は、plnkr.co
edit /

65

@ギュンターの答えは正しいです。さらに別の方法を提案したかっただけです。

@Component()-decorator 内にホストバインディングを追加することもできます。次のように、イベントと目的の関数呼び出しをhost-metadata-propertyに配置できます。

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  host: {
    '(window:resize)': 'onResize($event)'
  }
})
export class AppComponent{
   onResize(event){
     event.target.innerWidth; // window width
   }
}

2
私はこのページのすべての方法を試しましたが、どれもうまくいかないようです。これに関する公式のドキュメントはありますか?
トマト

読み込み時にビューポートの高さはどのように取得されますか?
Giridhar Karnik 2017

@GiridharKarnik、window.innerWidth内部ngOnInit、またはngAfterViewInitメソッドをやってみましたか?
ジョン

@Tomato APIリファレンスはここにあります。リファレンスの多くは自動生成されていると思いますが(おそらく)、例や詳細な説明はありません。いくつかのapi-referencesには多くの例があります。私はこれについてのドキュメントから具体的な例を見つけることができませんでした。多分それはどこかに隠されています:P
ジョン

1
これがその使用方法のリファレンスです
Anand Rockzz

52

私はこれがずっと前に尋ねられたことを知っていますが、今これを行うより良い方法があります!だれでもこの答えを見られるかどうかはわかりません。明らかにあなたのインポート:

import { fromEvent, Observable, Subscription } from "rxjs";

次に、コンポーネントで:

resizeObservable$: Observable<Event>
resizeSubscription$: Subscription

ngOnInit() {
    this.resizeObservable$ = fromEvent(window, 'resize')
    this.resizeSubscription$ = this.resizeObservable$.subscribe( evt => {
      console.log('event: ', evt)
    })
}

その後、destroyで必ずサブスクライブ解除してください!

ngOnDestroy() {
    this.resizeSubscription$.unsubscribe()
}

それが私にとってうまくいった唯一の方法です。ありがとう!! :-) ...インポートを調整する必要がありました。おそらく、私のrxjsは新しいものです:import { fromEvent, Observable,Subscription } from "rxjs";
Jette

これにdebounce(1000)をどこに追加できますか?
Deepak Thomas

3
返信が遅くなって申し訳ありません。デバウンスを追加するには、次のように使用しますthis.resizeSubscription$ = this.resizeObservable$.pipe(debounceTime(1000)).subscribe( evt => { console.log('event: ', evt) })
Chris Stanley

41

これを行う正しい方法は、EventManagerクラスを使用してイベントをバインドすることです。これにより、Angular Universalを使用したサーバー側レンダリングなど、コードを代替プラットフォームで機能させることができます。

import { EventManager } from '@angular/platform-browser';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import { Injectable } from '@angular/core';

@Injectable()
export class ResizeService {

  get onResize$(): Observable<Window> {
    return this.resizeSubject.asObservable();
  }

  private resizeSubject: Subject<Window>;

  constructor(private eventManager: EventManager) {
    this.resizeSubject = new Subject();
    this.eventManager.addGlobalEventListener('window', 'resize', this.onResize.bind(this));
  }

  private onResize(event: UIEvent) {
    this.resizeSubject.next(<Window>event.target);
  }
}

コンポーネントでの使用方法は、このサービスをプロバイダーとしてapp.moduleに追加し、コンポーネントのコンストラクターにインポートするだけです。

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'my-component',
  template: ``,
  styles: [``]
})
export class MyComponent implements OnInit {

  private resizeSubscription: Subscription;

  constructor(private resizeService: ResizeService) { }

  ngOnInit() {
    this.resizeSubscription = this.resizeService.onResize$
      .subscribe(size => console.log(size));
  }

  ngOnDestroy() {
    if (this.resizeSubscription) {
      this.resizeSubscription.unsubscribe();
    }
  }
}

これは、私が知る限り、モバイルで発火することはありません。このアプローチでどのように初期ウィンドウサイズを取得しますか?
user3170530 2017

windowサーバーにがないのと同じように、モバイルにはオブジェクトがありませんwindow。私はさまざまなモバイル構成に精通していませんが、上記のコードを適切なグローバルイベントリスナーにバインドするように簡単に調整できるはずです
cgatian

@cgatian私は初心者ですが、これは正しい答えのようです。残念ながら、サブスクリプションを作成することができません。コンポーネントにログインしてください。更新を確認できるように、コンポーネントでこれをサブスクライブする方法を回答に追加できますか?
マシューハーウッド2017

@cgatian私はプランカーを作りますが、これはうまくいかなかったようです。サービス内のフィルターは奇妙なようですstackoverflow.com/q/46397531/1191635
Matthew Harwood

3
@cgatian Mobile does not have a window object....モバイルブラウザにウィンドウオブジェクトがないのはなぜですか。
ドレナイ

31

ここにそれを行うためのより良い方法があります。Birowskyの回答に基づく。

ステップ1:angular serviceRxJS Observablesでを作成します。

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

@Injectable()
export class WindowService {
    height$: Observable<number>;
    //create more Observables as and when needed for various properties
    hello: string = "Hello";
    constructor() {
        let windowSize$ = new BehaviorSubject(getWindowSize());

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

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

}

function getWindowSize() {
    return {
        height: window.innerHeight
        //you can sense other parameters here
    };
};

ステップ2:上記serviceを挿入しObservables、サービス内で作成されたウィンドウのサイズ変更イベントを受け取りたい場所にサブスクライブします。

import { Component } from '@angular/core';
//import service
import { WindowService } from '../Services/window.service';

@Component({
    selector: 'pm-app',
    templateUrl: './componentTemplates/app.component.html',
    providers: [WindowService]
})
export class AppComponent { 

    constructor(private windowService: WindowService) {

        //subscribe to the window resize event
        windowService.height$.subscribe((value:any) => {
            //Do whatever you want with the value.
            //You can also subscribe to other observables of the service
        });
    }

}

リアクティブプログラミングを正しく理解することは、常に困難な問題を克服するのに役立ちます。これが誰かを助けることを願っています。


これはエラーだと思います:this.height $ =(windowSize $ .pluck( 'height')as Observable <number>)。distinctUntilChanged(); Observable <number>)。distinctUntilChanged(); あなたはdistinctUntilChanged()に2回続けて貼り付けたようです
Zuriel

わかりませんでした。詳しく説明してください。
Giridhar Karnik

Angularの外部でこのイベントを実行しているので、変更検出は発生しません。それが彼の意図したことだと信じてください。
Mark Pieszak-Trilon.io 2017年

1
「pluck」がBehaviorSubject型に存在しないというエラーが発生しました。コードをthis.height $ = windowSize $ .map(x => x.height)に変更するとうまくいきました。
マットサグデン2017

@GiridharKamik 1つの単純なサブスクライブで幅と高さの両方をサブスクライブできる、幅と高さを同時にサブスクライブするソリューションを提供できますか
ghiscoding

11

私が話して誰も見たことがないMediaMatcherのをangular/cdk

MediaQueryを定義してリスナーをアタッチできます。Matcherが一致した場合は、テンプレート(またはts)の任意の場所で何かを呼び出すことができます。 LiveExample

App.Component.ts

import {Component, ChangeDetectorRef} from '@angular/core';
import {MediaMatcher} from '@angular/cdk/layout';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  mobileQuery: MediaQueryList;

  constructor(changeDetectorRef: ChangeDetectorRef, media: MediaMatcher) {
    this.mobileQuery = media.matchMedia('(max-width: 600px)');
    this._mobileQueryListener = () => changeDetectorRef.detectChanges();
    this.mobileQuery.addListener(this._mobileQueryListener);
  }

  private _mobileQueryListener: () => void;

  ngOnDestroy() {
    this.mobileQuery.removeListener(this._mobileQueryListener);
  }

}

App.Component.Html

<div [class]="mobileQuery.matches ? 'text-red' : 'text-blue'"> I turn red on mobile mode 
</div>

App.Component.css

.text-red { 
   color: red;
}

.text-blue {
   color: blue;
}

ソース:https : //material.angular.io/components/sidenav/overview


6

600px未満がモバイルを意味すると仮定すると、このオブザーバブルを使用してサブスクライブできます。

まず、現在のウィンドウサイズが必要です。そこで、現在のウィンドウサイズという単一の値のみを出力するオブザーバブルを作成します。

initial$ = Observable.of(window.innerWidth > 599 ? false : true);

次に、別のオブザーバブルを作成して、ウィンドウサイズがいつ変更されたかを知る必要があります。これには、「fromEvent」演算子を使用できます。:事業者が訪問を喜ばrxjs`sについて詳しく学ぶにはrxjs

resize$ = Observable.fromEvent(window, 'resize').map((event: any) => {
  return event.target.innerWidth > 599 ? false : true;
 });

これら2つのストリームをマージして、オブザーバブルを受け取ります。

mobile$ = Observable.merge(this.resize$, this.initial$).distinctUntilChanged();

これで、次のようにサブスクライブできます。

mobile$.subscribe((event) => { console.log(event); });

退会を忘れないでください:)


5

Angular CDKにはViewportRulerサービスがあります。これはゾーンの外で実行され、サーバー側のレンダリングでも機能します。


2
これは受け入れられる答えになるはずです。必要なものがすべてあります+これは角度付きのCDK組み込み機能です。
Deniss M.

3

@cgatianのソリューションに基づいて、私は次の簡略化を提案します。

import { EventManager } from '@angular/platform-browser';
import { Injectable, EventEmitter } from '@angular/core';

@Injectable()
export class ResizeService {

  public onResize$ = new EventEmitter<{ width: number; height: number; }>();

  constructor(eventManager: EventManager) {
    eventManager.addGlobalEventListener('window', 'resize',
      e => this.onResize$.emit({
        width: e.target.innerWidth,
        height: e.target.innerHeight
      }));
  }
}

使用法:

import { Component } from '@angular/core';
import { ResizeService } from './resize-service';

@Component({
  selector: 'my-component',
  template: `{{ rs.onResize$ | async | json }}`
})
export class MyComponent {
  constructor(private rs: ResizeService) { }
}

これが最良の解決策であることがわかりましたが、これはウィンドウのサイズが変更された場合にのみ機能し、ロード時やルーターが変更された場合には機能しません。ルーターの変更、リロード、またはロードを適用する方法を知っていますか?
jcdsr 2018年

サービスに関数を追加して、コンポーネント@jcdsrでトリガーできます。getScreenSize(){this.onResize $ .emit({width:window.innerWidth、height:window.innerHeight}); }
DanielWaw

3

これは質問に対する正確な回答ではありませんが、任意の要素のサイズ変更を検出する必要がある人を助けることができます。

resized任意の要素(Angular Resize Event)にイベントを追加するライブラリを作成しました。

CSS要素のクエリResizeSensorから内部的に使用されます。

使用例

HTML

<div (resized)="onResized($event)"></div>

TypeScript

@Component({...})
class MyComponent {
  width: number;
  height: number;

  onResized(event: ResizedEvent): void {
    this.width = event.newWidth;
    this.height = event.newHeight;
  }
}

ウィンドウのサイズ変更を検出する場合、Angular Material Breakpoint Observerはすでにmaterial.angular.io/cdk/layout/overviewを
Darren Street

しかし、これはウィンドウのサイズ変更だけでなく、要素のサイズ変更も検出しません。
Martin Volek、

2

私が書いたこのlibが角度のコンポーネントの境界のサイズ変更(リサイズ)一度検索し、もこのヘルプ他の人に。あなたはそれをルートコンポーネントに置くことができ、ウィンドウのサイズ変更と同じことをします。

ステップ1:モジュールをインポートする

import { BoundSensorModule } from 'angular-bound-sensor';

@NgModule({
  (...)
  imports: [
    BoundSensorModule,
  ],
})
export class AppModule { }

ステップ2:以下のようなディレクティブを追加します

<simple-component boundSensor></simple-component>

ステップ3:境界サイズの詳細を受け取る

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

@Component({
  selector: 'simple-component'
  (...)
})
class SimpleComponent {
  @HostListener('resize', ['$event'])
  onResize(event) {
    console.log(event.detail);
  }
}

1

Angular2(2.1.0)では、ngZoneを使用して画面変更イベントをキャプチャします。

例を見てみましょう:

import { Component, NgZone } from '@angular/core';//import ngZone library
...
//capture screen changed inside constructor
constructor(private ngZone: NgZone) {
    window.onresize = (e) =>
    {
        ngZone.run(() => {
            console.log(window.innerWidth);
            console.log(window.innerHeight);
        });
    };
}

これがお役に立てば幸いです。


1

以下のコードでは、Angularの特定のdivのサイズの変化を観察できます。

<div #observed-div>
</div>

次にコンポーネントで:

oldWidth = 0;
oldHeight = 0;

@ViewChild('observed-div') myDiv: ElementRef;
ngAfterViewChecked() {
  const newWidth = this.myDiv.nativeElement.offsetWidth;
  const newHeight = this.myDiv.nativeElement.offsetHeight;
  if (this.oldWidth !== newWidth || this.oldHeight !== newHeight)
    console.log('resized!');

  this.oldWidth = newWidth;
  this.oldHeight = newHeight;
}

最大幅767pxで変数= 6からカウント= 0に変数を変更したいのですが、どうすればよいですか?
Thanveer Shah

0

すべてのソリューションがサーバー側または角度ユニバーサルで機能していません


0

私はこれらの答えのほとんどをチェックしました。次に、レイアウトに関するAngularのドキュメントを確認することにしました。

Angularにはさまざまなサイズを検出するための独自のオブザーバーがあり、コンポーネントやサービスに簡単に実装できます。

簡単な例は次のとおりです。

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

@Component({...})
class MyComponent {
  constructor(breakpointObserver: BreakpointObserver) {
    breakpointObserver.observe([
      Breakpoints.HandsetLandscape,
      Breakpoints.HandsetPortrait
    ]).subscribe(result => {
      if (result.matches) {
        this.activateHandsetLayout();
      }
    });
  }
}

それが役に立てば幸い

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