각도 창 크기 조정 이벤트


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
실제로 각도 문제는 아닙니다. 상기 보는 객체입니다. 그것 innerHeightinnerWidth속성을 얻을 수 있습니다 ..
Sasxa

1
@Sasxa이 올바른지, 당신은 할 필요가console.log(event.target.innerWidth )
판 카즈 Parkar

정보 Sasxa / Pankaj에 감사드립니다-나는 그것이 단순한 자바 스크립트 일인지 Typescript 일인지 Angular 이벤트 일지 확실하지 않았습니다. 나는 여기에 매우 가파른 학습 곡선을 오르고 있으며 귀하의 의견에 감사드립니다.
DanAbdn

답변:


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

또는 HostListener 데코레이터 사용 :

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

지원되는 글로벌 목표는 window, document하고 body.

https://github.com/angular/angular/issues/13248 이 Angular로 구현 될 때까지 성능이 DOM 이벤트를 필수적으로 구독하고 RXJS를 사용하여 다른 답변 중 일부에 표시된 것처럼 이벤트 양을 줄이는 것이 좋습니다.


15
사용하는 구문에 대한 설명서가 있습니까 : window : resize ?
Clement

3
바로 그거죠. 당신은 사용할 수 있습니다 document, window그리고 body github.com/angular/angular/blob/...
귄터 Zöchbauer을

5
완벽한 답변 .. @HostListener가 더 깔끔한 방법이라고 생각합니다 :)하지만 다음을 사용하여 HostListener를 먼저 가져와야합니다.import { Component, OnInit, HostListener } from '@angular/core';
Gaurav Sharma

4
빠른 팁 : 첫 번째로드에서도 트리거하려면 @ angular / core에서 ngAfterViewInit를 구현하십시오. angular.io/api/core/AfterViewInit
Zymotik

7
그러나 debounceTime과 함께 HostListener의 작동 방식을 알고 싶은 분은 plnkr.co/edit/3J0dcDaLTJBxkzo8Akyg?p=preview
jcdsr

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

@GiridharKarnik, window.innerWidth내부 ngOnInit또는 ngAfterViewInit방법 을 시도 했습니까?
John

@Tomato API 참조는 여기 에서 찾을 수 있습니다 . 많은 참조는 자동 생성되며 (예상) 예제 나 자세한 설명이 부족합니다. 일부 API 참조에는 많은 예가 있습니다. 나는 이것에 관한 문서에서 구체적인 예를 찾을 수 없었다. 어딘가에 숨겨져있을 것입니다 : P
John

1
여기에 그 사용 방법에 대한 참조입니다
아난드 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)
    })
}

그런 다음 파괴를 구독 취소하십시오!

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

window서버에 객체 가없는 것처럼 모바일에는 객체가 없습니다 window. 임 다른 모바일 구성에 대해 잘 알고 있지만, 당신은 쉽게 올바른 글로벌 이벤트 리스너에 바인딩 위의 코드를 적용 할 수 있어야하지
cgatian

@ cgatian 나는 멍청한 사람이지만 이것은 정답처럼 보입니다. 불행히도 나는 가입을 만드는 행운이 없다. 구성 요소에 로그인하십시오. 업데이트를 볼 수 있도록 구성 요소에서 이것을 구독하는 방법을 답변에 추가 할 수 있습니까?
Matthew Harwood

@ cgatian 나는 plunker를 만들 것입니다 그러나 이것은 작동하지 않는 것 같았습니다. 서비스의 필터는 이상하게 보인다 stackoverflow.com/q/46397531/1191635
Matthew Harwood

3
@cgatian Mobile does not have a window object.... 왜 모바일 브라우저에 윈도우 객체가 없다고 생각하십니까?
Drenai

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 (에 붙여 좋아
Zuriel

나는 당신을 얻지 못했습니다, eloborate 바랍니다.
Giridhar Karnik

Angular 외부에서이 이벤트를 수행하면 변경 감지가 시작되지 않습니다. 이것이 그가 의미 한 바라고 생각하십시오.
Mark Pieszak-Trilon.io

1
BehaviorSubject 유형에 'pluck'이 존재하지 않는다는 오류가 발생했습니다. 코드를 this.height $ = windowSize $ .map (x => x.height)으로 변경하면 나에게 도움이되었습니다.
Matt Sugden

@GiridharKamik 너비와 높이를 동시에 구독 할 수있는 솔루션을 제공 할 수 있습니까? 너비와 높이를 모두 간단한 구독으로 구독 할 수 있습니다
ghiscoding

11

나는 대한 사람의 이야기를 보지 못했어요 MediaMatcherangular/cdk.

MediaQuery를 정의하고 리스너를 첨부 할 수 있습니다. 그런 다음 Matcher가 일치하는 경우 템플리트 (또는 ts)의 어느 곳에서나 컨텐츠를 호출 할 수 있습니다. 라이브 예

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가 사용자에게 모바일을 의미한다고 가정하면이 관찰 가능 항목을 사용하여 구독 할 수 있습니다.

먼저 현재 창 크기가 필요합니다. 따라서 현재 창 크기라는 단일 값만 방출하는 Observable을 만듭니다.

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

그런 다음 창 크기가 언제 변경되었는지 알 수 있도록 다른 관찰 가능 객체를 만들어야합니다. 이를 위해 "fromEvent"연산자를 사용할 수 있습니다. rxjs의 운영자에 대한 자세한 내용을 보려면 다음 사이트를 방문하십시오 : rxjs

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

이 두 개 스트림을 합병하여 관찰 가능한 것을 받으십시오.

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

이제 다음과 같이 구독 할 수 있습니다.

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

구독을 취소하십시오 :)


5

각도 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

서비스에 함수를 추가하고 컴포넌트 @jcdsr에서 트리거 할 수 있습니다. getScreenSize () {this.onResize $ .emit ({width : window.innerWidth, height : window.innerHeight}); }
DanielWaw

3

이것은 질문에 대한 정확한 대답은 아니지만 모든 요소의 크기 변화를 감지 해야하는 사람에게 도움이 될 수 있습니다.

resized요소 -Angular Resize Event에 이벤트를 추가하는 라이브러리를 만들었습니다 .

내부적 ResizeSensor으로 CSS Element Queries 에서 사용합니다 .

사용법 예

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

당신은 윈도우가 벌써 각도 재료 중단 점 관찰자 핸들의 크기를 조정 감지 할 경우 material.angular.io/cdk/layout/overview
대런 거리를

그러나 이것은 창 크기 조정 만 감지하지 않고 모든 요소 크기 조정을 감지합니다.
Martin Volek

2

Angular에서 구성 요소 경계 크기 변경 (크기 조정)을 찾으면 이 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에서 varibale을 counter = 6에서 count = 0으로 변경하고 싶습니다. 어떻게합니까?
Thanveer Shah

0

모든 솔루션이 서버 측 또는 각도 범용으로 작동하지 않습니다


0

나는 대부분의 답변을 확인했다. 그런 다음 Layout의 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.