Wykrywanie zmian rozmiaru okna w czasie rzeczywistym w Angular 4


118

Próbowałem zbudować responsywny pasek nawigacyjny i nie chcę używać zapytania o media, więc zamierzam użyć *ngIFjako kryterium rozmiaru okna. Ale napotkałem problem, ponieważ nie mogę znaleźć żadnej metody ani dokumentacji dotyczącej wykrywania rozmiaru okna Angular 4. Próbowałem również metody JavaScript, ale nie jest ona obsługiwana.

Próbowałem również następujących rzeczy :

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

... który był używany w jonowym.

I screen.availHeight, ale nadal bez sukcesu.


1
O co platformchodzi? Czy chodzi o Ionic?
Günter Zöchbauer

@ Günter Zöchbauer Platforma jest kanciasta, chciałem tylko wspomnieć o kodach, które wypróbowałem.
Ronit Oommen

1
Platformjest usługą jonową. Więc zgaduję, że to projekt Ionic?
robbannn


@BlackBeard Nie wydaje mi się, żeby to był duplikat ze względu na różnice między Angular 2 i 4.
tehlivi

Odpowiedzi:


261

Aby uzyskać to na init

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

Jeśli chcesz, aby był aktualizowany przy zmianie rozmiaru:

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

2
this.innerWidth = event.target.innerWidth; ... jest prawdopodobnie bardziej wydajna, daje ten sam wynik
danday74

2
Zalecamy również to w konstruktorze, jeśli używasz lodash ... this.onResize = debounce (this.onResize, 150, {lead: false, trailing: true}) ... aby zapobiec zbyt częstemu wywoływaniu metody onResize. . będziesz musiał ... zaimportować {debounce} z „lodash”
danday74

Myślę, że wolałem użyć ngAfterViewInitmetody haka na życie zamiast metody na ngOnInit życie
ahmed hamdy

40

Jeśli chcesz zareagować na określone punkty przerwania (np. Zrobić coś, jeśli szerokość jest mniejsza niż 768px), możesz również użyć BreakpointObserver:

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

{ ... }

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

lub nawet posłuchaj zmian w tym punkcie przerwania:

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

jeśli chcesz działać tylko wtedy, gdy obserwator spełnia kryteria, które musisz dodać wewnątrz, zasubskrybuj to w if (result.matches)przeciwnym razie zadzwoni, nawet jeśli nie
karoluS

1
@karoluS: Tak, oczywiście. Zredagowałem odpowiedź, żeby to wyjaśnić. Dziękuję Ci.
Jeremy Benks

Wygląda na to, że cdkma to zależność równorzędną od określonej wersji kątowej. Jak 7, jeśli chodzi o najnowsze. Zresztą mogę tego użyć do starszej wersji (kątowej 4 jak w pytaniu)?
LeOn - Han Li

@Leon li: Właściwie używam Angular 7, zgadza się. Jednak: O ile wiem, możesz użyć cdk również w Angular 4. Zgodnie z tym wpisem na blogu potrzebujesz cdk 2.x. O ile mi wiadomo, trzeba to zainstalować ręcznie iz wersją określoną w ten sposób: npm @ angular / cdk @ 4
Jeremy Benks

@JeremyBenks Y, używamy w 4.2.6szczególności ng . Nie można znaleźć wersji cdk 2.x, tylko 4.1.x i 4.3.x. W każdym razie, dzięki!
LeOn - Han Li

9

Jeśli chcesz, aby komponenty były łatwe do testowania, powinieneś opakować globalny obiekt okna w usługę Angular:

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

@Injectable()
export class WindowService {

  get windowRef() {
    return window;
  }

}

Następnie możesz wstrzyknąć go jak każdą inną usługę:

constructor(
    private windowService: WindowService
) { }

I konsumuj ...

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

2
Nie widzę sensu wykonywania usługi, aby zrobić dokładnie to, co jest już pod ręką. window.innerWidth.
Rodrigo

1
Po pierwsze, DI jest metodą Angular i sprawia, że ​​zależności komponentu / dyrektywy są wyraźniejsze. Ale głównym punktem, o którym tutaj wspomniano, jest ułatwienie testowania kodu korzystającego z usługi. Korzystając z tego podejścia, WindowService może być mockowany w dowolnym teście napisanym dla komponentów korzystających z usługi.
Kildareflare,

9

W dokumentacji dla Platform width()i height()stwierdzono, że te metody używają odpowiednio window.innerWidthi window.innerHeight. Jednak preferowane jest używanie tych metod, ponieważ wymiary są wartościami zapisanymi w pamięci podręcznej, co zmniejsza ryzyko wielokrotnych i kosztownych odczytów 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();
    });
}

Jak się widthz windowdotyczyć DOM? Logicznie rzecz biorąc, nie powinno zależeć od tego, jak wygląda drzewo dom.
Shahryar Saljoughi

7

To jest przykład usługi, z której korzystam.

Możesz uzyskać szerokość ekranu, subskrybując screenWidth$lub przezscreenWidth$.value .

To samo dotyczy mediaBreakpoint$(lub 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');
    }
  }

}

Mam nadzieję, że to komuś pomoże


Moja ulubiona odpowiedź! Po prostu upewnij się, że dodałeś this.init () w konstruktorze, aby działał.
Ben


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

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

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

3
Zawsze wyjaśniaj, dlaczego może to być właściwe rozwiązanie
thedp

3

Odpowiedź jest bardzo prosta. napisz poniższy kod

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

W tym scenariuszu można użyć metody pobierającej tekst. Lubię to

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

I użyj tego w szablonie w ten sposób:

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

Nie będziesz potrzebować żadnego programu obsługi zdarzeń, aby sprawdzić zmianę rozmiaru / okna, ta metoda sprawdzi rozmiar za każdym razem automatycznie.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.