web-dev-qa-db-ja.com

Angular ウィンドウサイズ変更イベント

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

現在私は次のように私の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);
    }
}

このイベントオブジェクトから幅と高さを取得する方法を教えてください。

ありがとう。

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

または

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

サポートされているグローバルターゲットはwindowdocument、およびbodyです。

https://github.com/angular/angular /issues/3248 がAngularに実装されるまでは、DOMイベントへのサブスクライブを必須とし、RXJSを使用してイベント数を削減するのがパフォーマンス上優れています。他の答えのいくつかに見られるように。

388

@ギュンターの答えは正しいです。私はまだ別の方法を提案したいと思いました。

@Component()-デコレータの中にHost-bindingを追加することもできます。次のように、イベントと必要な関数呼び出しを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
   }
}
53
John

これを行う正しい方法は、 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();
    }
  }
}
33
cgatian

これを実行するためのより良い方法です。 Birowskyの answerに基づく。

ステップ1:RxJS Observablesangular serviceを作成します。

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
        });
    }

}

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

28
GriffinTaimer

私はこれがずっと前に頼まれたことを知っています、しかし今これをするためのより良い方法があります!だれかがこの答えを見るかどうか私にはわかりません。明らかにあなたの輸入品:

import { fromEvent } from "rxjs/observable/fromEvent";
import { Observable } from "rxjs/Observable";
import { Subscription } from "rxjs/Subscription";

それからあなたのコンポーネントで:

resizeObservable$: Observable<Event>
resizeSubscription$: Subscription

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

それから、破棄の登録を解除してください!

ngOnDestroy() {
    this.resizeSubscription$.unsubscribe()
}
21
Chris Stanley

誰もがangular/cdkMediaMatcherについて話しているのを見たことがありません。

MediaQueryを定義してそれにリスナーをアタッチすることができます - そしてテンプレート(またはts)のどこでもMatcherがマッチすればものを呼び出すことができます。 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

7
Stavm

<600pxがあなたにとってモバイルであることを意味すると仮定すると、このオブザーバブルを使用してそれを購読することができます。

まず、現在のウィンドウサイズが必要です。そのため、単一の値(現在のウィンドウサイズ)のみを出力する観測量を作成します。

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

それから、ウィンドウサイズがいつ変更されたかがわかるように、別の観測量を作成する必要があります。これには "fromEvent"演算子を使うことができます。 rxjsの演算子の詳細については、次のURLをご覧ください。 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); });

退会することを忘れないでください:)

6
Flosut Mözil

@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) { }
}
3
Johannes Hoppe

これは質問に対する正確な答えではありませんが、あらゆる要素のサイズの変化を検出する必要がある人に役立ちます。

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

内部的には CSS Element Queries からの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;
  }
}
2
Martin Volek

このlib はAngularでコンポーネントの境界サイズの変更(サイズ変更)を行ったことを見つけるために書きました。これは他の人々に役立つかもしれません。あなたはそれをルートコンポーネントに置くかもしれません、ウィンドウサイズ変更と同じことをするでしょう。

ステップ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);
  }
}
2
PRAISER

On Angular 2(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
Anh Hoang

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

0
Totati

以下のコードは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;
}
0
abedfar