Mendeteksi perubahan ukuran jendela waktu nyata di Angular 4

118

Saya telah mencoba membangun bilah navigasi yang responsif dan tidak ingin menggunakan kueri media, jadi saya bermaksud menggunakan *ngIFukuran jendela sebagai kriteria. Tetapi saya telah menghadapi masalah karena saya tidak dapat menemukan metode atau dokumentasi apa pun tentang deteksi ukuran jendela Angular 4. Saya juga mencoba metode JavaScript, tetapi tidak didukung.

Saya juga telah mencoba yang berikut ini :

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

... yang digunakan dalam ionik.

Dan screen.availHeight, tapi tetap tidak berhasil.

Ronit Oommen
sumber
1
Tentang apa platform? Apakah ini tentang Ionic?
Günter Zöchbauer
@ Günter Zöchbauer Platformnya bersudut, hanya ingin menyebutkan kode yang telah saya coba.
Ronit Oommen
1
Platformadalah layanan ionik. Jadi saya rasa ini adalah proyek ionik?
robbannn
@BlackBeard Saya tidak berpikir itu duplikat karena seberapa banyak Angular 2 dan 4 berbeda.
tehlivi

Jawaban:

261

Untuk mendapatkannya di init

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

Jika Anda ingin terus memperbaruinya saat diubah ukurannya:

@HostListener('window:resize', ['$event'])
onResize(event) {
  this.innerWidth = window.innerWidth;
}
Eduardo Vargas
sumber
2
this.innerWidth = event.target.innerWidth; ... mungkin lebih efisien, menghasilkan hasil yang sama
danday74
2
Juga rekomendasikan ini di konstruktor jika Anda menggunakan lodash ... this.onResize = debounce (this.onResize, 150, {leading: false, trailing: true}) ... untuk mencegah metode onResize dipanggil terlalu sering .. . Anda perlu ... mengimpor {debounce} dari 'lodash'
danday74
Saya pikir lebih suka menggunakan ngAfterViewInitmetode kail hidup daripada ngOnInit metode kail
ahmed hamdy
39

Jika Anda ingin bereaksi pada breakpoint tertentu (misalnya melakukan sesuatu jika lebarnya kurang dari 768px), Anda juga dapat menggunakan BreakpointObserver:

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

{ ... }

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

atau bahkan mendengarkan perubahan pada breakpoint itu:

breakpointObserver.observe([
  '(max-width: 768px)'
    ]).subscribe(result => {
      if (result.matches) {
        doSomething();
      } else {
        // if necessary:
        doSomethingElse();
      }
    });
Jeremy Benks
sumber
jika Anda ingin bertindak hanya jika pengamat cocok dengan kriteria Anda harus menambahkan di dalam berlangganan ini if (result.matches)jika tidak maka akan memanggil bahkan jika tidak
karoluS
1
@ KaroluS: Ya tentu saja. Saya mengedit jawaban saya untuk memperjelasnya. Terima kasih.
Jeremy Benks
Tampaknya ini cdkmemiliki ketergantungan rekan pada versi sudut tertentu. Like 7 untuk yang terbaru. Pokoknya saya bisa menggunakan ini untuk versi yang lebih lama (sudut 4 seperti dalam pertanyaan)?
LeOn - Han Li
@ Leon li: Saya sebenarnya menggunakan sudut 7, itu benar. Namun: Sejauh yang saya tahu Anda dapat menggunakan cdk di angular 4 juga. Menurut posting blog ini Anda membutuhkan cdk 2.x. Sejauh yang saya tahu, ini harus diinstal secara manual dan dengan versi yang ditentukan seperti ini: npm @ angular / cdk @ 4
Jeremy Benks
@JeremyBenks Y, kami menggunakan ng 4.2.6secara khusus. Tidak dapat menemukan versi cdk 2.x itu, hanya 4.1.x dan 4.3.x. Terima kasih!
LeOn - Han Li
9

Jika Anda ingin komponen Anda mudah diuji, Anda harus menggabungkan objek global window dalam Angular Service:

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

@Injectable()
export class WindowService {

  get windowRef() {
    return window;
  }

}

Anda kemudian dapat menyuntikkannya seperti layanan lainnya:

constructor(
    private windowService: WindowService
) { }

Dan konsumsi ...

  ngOnInit() {
      const width= this.windowService.windowRef.innerWidth;
  }
Kildareflare
sumber
2
Saya tidak dapat melihat gunanya melakukan layanan untuk melakukan apa yang sudah ada. window.innerWidth.
Rodrigo
1
Pertama DI adalah cara Angular dan membuat dependensi dari sebuah komponen / direktif lebih jelas. Tetapi poin utama yang disebutkan di sini adalah membuat kode yang menggunakan layanan lebih mudah untuk diuji. Dengan menggunakan pendekatan ini, WindowService dapat diolok-olok dalam tes apa pun yang ditulis untuk komponen yang menggunakan layanan.
Kildareflare
9

Dokumentasi untuk Platform width()dan height(), disebutkan bahwa metode ini menggunakan window.innerWidthdan window.innerHeightmasing - masing. Namun menggunakan metode lebih disukai karena dimensinya adalah nilai yang disimpan dalam cache, yang mengurangi kemungkinan pembacaan beberapa kali dan DOM yang mahal.

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
sumber
Bagaimana hubungannya dengan get widthof ? Logikanya, itu tidak harus bergantung pada seperti apa pohon dom itu. windowDOM
Shahryar Saljoughi
6

Ini adalah contoh layanan yang saya gunakan.

Anda bisa mendapatkan lebar layar dengan berlangganan screenWidth$, atau melalui screenWidth$.value.

Hal yang sama untuk mediaBreakpoint$(atau 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');
    }
  }

}

Semoga ini bisa membantu seseorang

Denis
sumber
Jawaban favorit saya! Pastikan Anda menambahkan this.init () di konstruktor agar berfungsi.
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
sumber
3
Selalu jelaskan mengapa ini mungkin solusi yang tepat
thedp
3

Jawabannya sangat sederhana. tulis kode di bawah ini

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
sumber
1

Anda dapat menggunakan metode pengambil skrip untuk skenario ini. Seperti ini

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

Dan gunakan itu di template seperti ini:

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

Anda tidak memerlukan pengendali kejadian untuk memeriksa pengubahan ukuran / jendela, metode ini akan memeriksa ukuran setiap saat secara otomatis.

Rohan Gayen
sumber