Erkennen von Änderungen der Fenstergröße in Echtzeit in Winkel 4

118

Ich habe versucht, eine reaktionsschnelle Navigationsleiste zu erstellen, und möchte keine Medienabfrage verwenden. Daher beabsichtige ich, *ngIFdie Fenstergröße als Kriterium zu verwenden. Ich hatte jedoch ein Problem, da ich keine Methode oder Dokumentation zur Erkennung der Angular 4-Fenstergröße finden konnte. Ich habe auch die JavaScript-Methode ausprobiert, sie wird jedoch nicht unterstützt.

Ich habe auch folgendes versucht :

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

... die in ionischen verwendet wurde.

Und screen.availHeightdoch immer noch kein Erfolg.

Ronit Oommen
quelle
1
Worum geht es platform? Geht es um Ionic?
Günter Zöchbauer
@ Günter Zöchbauer Die Plattform ist eckig, wollte nur die Codes erwähnen, die ich ausprobiert hatte.
Ronit Oommen
1
Platformist ein ionischer Dienst. Ich vermute also, dass es ein ionisches Projekt ist?
Robbannn
@BlackBeard Ich glaube nicht, dass es ein Duplikat ist, da sich Angular 2 und 4 stark unterscheiden.
Tehlivi

Antworten:

259

Um es auf init zu bekommen

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

Wenn Sie die Größe ändern möchten:

@HostListener('window:resize', ['$event'])
onResize(event) {
  this.innerWidth = window.innerWidth;
}
Eduardo Vargas
quelle
2
this.innerWidth = event.target.innerWidth; ... ist möglicherweise effizienter, produziert das gleiche Ergebnis
danday74
2
Empfehlen Sie dies auch im Konstruktor, wenn Sie lodash verwenden ... this.onResize = debounce (this.onResize, 150, {führend: falsch, nachlaufend: wahr}) ... um zu verhindern, dass die onResize-Methode zu häufig aufgerufen wird. Sie müssen ... {debounce} von 'lodash'
importieren
Ich denke, es ist vorzuziehen, die ngAfterViewInitLife-Hook-Methode anstelle der ngOnInit Life-Hook-Methode zu verwenden
ahmed hamdy
39

Wenn Sie auf bestimmte Haltepunkte reagieren möchten (z. B. etwas tun, wenn die Breite weniger als 768 Pixel beträgt), können Sie auch BreakpointObserver verwenden:

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

{ ... }

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

oder hören Sie sich sogar Änderungen an diesem Haltepunkt an:

breakpointObserver.observe([
  '(max-width: 768px)'
    ]).subscribe(result => {
      if (result.matches) {
        doSomething();
      } else {
        // if necessary:
        doSomethingElse();
      }
    });
Jeremy Benks
quelle
Wenn Sie nur dann handeln möchten, wenn der Beobachter die Kriterien erfüllt, die Sie hinzufügen müssen, abonnieren Sie dies. if (result.matches)Andernfalls wird er aufgerufen, auch wenn dies nicht der
Fall ist
1
@ KaroluS: Ja natürlich. Ich habe meine Antwort bearbeitet, um das klar zu machen. Danke dir.
Jeremy Benks
Scheint, dass dies cdkPeer-Abhängigkeit von einer bestimmten Version des Winkels hat. Wie 7 für die neuesten. Wie auch immer, ich kann dies für ältere Versionen verwenden (Winkel 4 wie in der Frage)?
LeOn - Han Li
@Leon li: Ich benutze eigentlich Winkel 7, das stimmt. Allerdings: Soweit ich weiß, können Sie cdk auch in Winkel 4 verwenden. Laut diesem Blog-Beitrag benötigen Sie cdk 2.x. Soweit ich weiß, muss dies manuell und mit der folgenden Version installiert werden: npm @ angle / cdk @ 4
Jeremy Benks
@JeremyBenks Y, wir verwenden ng 4.2.6speziell. Es kann keine CDK 2.x-Version gefunden werden, nur 4.1.x und 4.3.x. Trotzdem danke!
LeOn - Han Li
9

Wenn Sie möchten, dass Ihre Komponenten leicht testbar bleiben, sollten Sie das globale Fensterobjekt in einen Angular Service einbinden:

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

@Injectable()
export class WindowService {

  get windowRef() {
    return window;
  }

}

Sie können es dann wie jeden anderen Dienst injizieren:

constructor(
    private windowService: WindowService
) { }

Und konsumieren ...

  ngOnInit() {
      const width= this.windowService.windowRef.innerWidth;
  }
Kildareflare
quelle
2
Ich kann den Sinn eines Dienstes nicht erkennen, um genau das zu tun, was er bereits zur Hand hat. window.innerWidth.
Rodrigo
1
Erstens ist DI der Winkelweg und macht die Abhängigkeiten einer Komponente / Direktive klarer. Der hier erwähnte Hauptpunkt besteht jedoch darin, den Code, der den Dienst verwendet, einfacher zu testen. Mit diesem Ansatz kann der WindowService in jedem Test verspottet werden, der für Komponenten geschrieben wurde, die den Service verwenden.
Kildareflare
9

Die Dokumentation Platform width()und height()es wird gesagt , dass diese Methoden verwenden window.innerWidthund window.innerHeightjeweils. Die Verwendung der Methoden wird jedoch bevorzugt, da die Dimensionen zwischengespeicherte Werte sind, was die Wahrscheinlichkeit mehrerer und teurer DOM-Lesevorgänge verringert.

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();
    });
}
Robbannn
quelle
In welcher Beziehung steht das Erhalten widthvon ? Logischerweise sollte es nicht davon abhängen, wie der Dombaum aussieht. windowDOM
Shahryar Saljoughi
6

Dies ist ein Beispiel für einen Dienst, den ich benutze.

Sie können die Bildschirmbreite durch Abonnieren screenWidth$oder über abrufenscreenWidth$.value .

Das gleiche gilt für mediaBreakpoint$(oder 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');
    }
  }

}

Hoffe das hilft jemandem

Denis
quelle
Meine Lieblingsantwort! Stellen Sie einfach sicher, dass Sie this.init () im Konstruktor hinzufügen, damit es funktioniert.
Ben
3
@HostListener("window:resize", [])
public onResize() {
  this.detectScreenSize();
}

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

private detectScreenSize() {
    const height = window.innerHeight;
    const width = window.innerWidth;
}
Dhruv Parekh
quelle
3
Erklären Sie immer, warum dies die richtige Lösung sein könnte
am
2

Die Antwort ist sehr einfach. Schreiben Sie den folgenden Code

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();
}
}
Harish Mahajan
quelle
1

Sie können für dieses Szenario die Typoskript-Getter-Methode verwenden. So was

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

Und verwenden Sie das in Vorlage wie folgt:

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

Sie benötigen keinen Ereignishandler, um die Größe des Fensters zu überprüfen. Diese Methode überprüft jedes Mal automatisch die Größe.

Rohan Gayen
quelle