Angular 4'te gerçek zamanlı pencere boyutu değişikliklerini algılama


118

Duyarlı bir gezinme çubuğu oluşturmaya çalışıyordum ve bir medya sorgusu kullanmak istemiyorum, bu yüzden *ngIFbir kriter olarak pencere boyutuyla kullanmayı planlıyorum . Ancak Angular 4 pencere boyutu algılamasında herhangi bir yöntem veya belge bulamadığım için bir sorunla karşı karşıyayım. JavaScript yöntemini de denedim, ancak desteklenmiyor.

Aşağıdakileri de denedim :

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

... iyonik olarak kullanıldı.

Ve screen.availHeightyine de başarı yok.


1
Ne platformhakkında? Bu Ionic ile mi ilgili?
Günter Zöchbauer

@ Günter Zöchbauer Platform köşeli, sadece denediğim kodlardan bahsetmek istedim.
Ronit Oommen

1
Platformİyonik bir hizmettir. Yani bunun iyonik bir proje olduğunu tahmin ediyorum?
robbannn


@BlackBeard Angular 2 ve 4'ün ne kadar farklı olmasından dolayı bunun bir kopya olduğunu sanmıyorum.
tehlivi

Yanıtlar:


261

Başlamak için

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

Yeniden boyutlandırmada güncel kalmasını istiyorsanız:

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

2
this.innerWidth = event.target.innerWidth; ... muhtemelen daha verimlidir, aynı sonucu verir
danday74

2
Ayrıca, lodash kullanıyorsanız ... this.onResize = debounce (this.onResize, 150, {lead: false, trailing: true}) ... onResize yönteminin çok sık çağrılmasını önlemek için yapıcıda bunu önerin. . 'lodash'tan {debounce} dosyasını içe aktarmanız gerekecek
danday74

Ben kullanmayı tercih düşünüyorum ngAfterViewInityerine ömür kanca yöntemi ngOnInit ömür kanca yöntemiyle
ahmed hamdy

40

Belirli kesme noktalarına tepki vermek istiyorsanız (örneğin, genişlik 768 pikselden azsa bir şeyler yapın), BreakpointObserver'ı da kullanabilirsiniz:

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

{ ... }

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

hatta bu kesme noktasındaki değişiklikleri dinleyin:

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

sadece gözlemci içeriye eklemeniz gereken kriterlere uyuyorsa harekete geçmek istiyorsanız abone olun, if (result.matches)aksi takdirde
yapmasa

1
@karoluS: Evet tabi ki. Bunu netleştirmek için cevabımı düzenledim. Teşekkür ederim.
Jeremy Benks

Görünüşe göre, bunun cdkbelirli bir açısal sürümüne bağımlılığı var. En son 7 gibi. Neyse bunu eski sürüm için kullanabilirim (soruda olduğu gibi açısal 4)?
LeOn - Han Li

@Leon li: Aslında açısal 7 kullanıyorum, bu doğru. Ancak: Bildiğim kadarıyla cdk'yi açısal 4'te de kullanabilirsiniz. Bu blog yazısına göre cdk 2.x'e ihtiyacınız var. Bildiğim kadarıyla, bunun manuel olarak ve şu şekilde belirtilen sürümle yüklenmesi gerekiyor: npm @ angular / cdk @ 4
Jeremy Benks

@JeremyBenks Y, 4.2.6özellikle ng kullanıyoruz . Bunun üzerinde bir cdk 2.x sürümü bulunamıyor, sadece 4.1.x ve 4.3.x. Neyse, teşekkürler!
LeOn - Han Li

9

Bileşenlerinizin kolayca test edilebilir kalmasını istiyorsanız, global pencere nesnesini bir Angular Service içine sarmalısınız:

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

@Injectable()
export class WindowService {

  get windowRef() {
    return window;
  }

}

Daha sonra herhangi bir hizmet gibi enjekte edebilirsiniz:

constructor(
    private windowService: WindowService
) { }

Ve tüketin ...

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

2
Zaten elinizde olan şeyi tam olarak yapmak için bir hizmet yapmanın amacını göremiyorum. window.innerWidth.
Rodrigo

1
İlk olarak DI, Angular yoldur ve bir bileşenin / yönergenin bağımlılıklarını daha net hale getirir. Ancak burada bahsedilen ana nokta, hizmeti kullanan kodu test etmeyi kolaylaştırmaktır. Bu yaklaşımı kullanarak WindowService, hizmeti kullanan bileşenler için yazılmış herhangi bir testte alay edilebilir.
Kildareflare

9

Belgeleri Platform width()ve height()halen bu yöntemlerin kullandığını dile getirilmiştir window.innerWidthve window.innerHeightsırasıyla. Ancak boyutlar önbelleğe alınmış değerler olduğu için yöntemlerin kullanılması tercih edilir, bu da birden çok ve pahalı DOM okuma olasılığını azaltır.

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

Nasıl oluyor mu widthait windowilgili DOM? Mantıksal olarak, dom ağacının neye benzediğine bağlı olmamalıdır.
Shahryar Saljoughi

7

Bu, kullandığım bir hizmet örneğidir.

Ekran genişliğini abone olarak screenWidth$veya aracılığıyla alabilirsinizscreenWidth$.value .

Aynısı mediaBreakpoint$(veya mediaBreakpoint$.value) için

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

}

Umarım bu birine yardımcı olur


En sevdiğim cevap! Çalışması için yapıcıya this.init () eklediğinizden emin olun.
Ben


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

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

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

3
Her zaman bunun neden doğru çözüm olabileceğini açıklayın
2019

3

Cevap çok basit. aşağıdaki kodu yaz

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

Bu senaryo için typcript getter yöntemini kullanabilirsiniz. Bunun gibi

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

Ve bunu şu şekilde bir şablonda kullanın:

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

Pencereyi yeniden boyutlandırmak için herhangi bir olay işleyicisine ihtiyacınız olmayacak, bu yöntem her seferinde boyutu otomatik olarak kontrol edecektir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.