Acara mengubah ukuran jendela sudut

232

Saya ingin melakukan beberapa tugas berdasarkan peristiwa ukuran kembali jendela (saat memuat dan secara dinamis).

Saat ini saya memiliki DOM saya sebagai berikut:

<div id="Harbour">
    <div id="Port" (window:resize)="onResize($event)" >
        <router-outlet></router-outlet>
    </div>
</div>

Acara dengan benar menyala

export class AppComponent {
   onResize(event) {
        console.log(event);
    }
}

Bagaimana cara mengambil Lebar dan Tinggi dari objek acara ini?

Terima kasih.

DanAbdn
sumber
6
Bukan pertanyaan Angular. lihat objek jendela . Anda bisa mendapatkannya innerHeightdan innerWidthproperti ..
Sasxa
1
@Sasxa benar, Anda hanya perlu melakukanconsole.log(event.target.innerWidth )
Pankaj Parkar
Terima kasih atas informasinya Sasxa / Pankaj - Saya tidak yakin apakah itu hanya hal javascript biasa atau hal naskah atau kejadian acara sudut. Saya mendaki kurva belajar yang sangat curam untuk diri saya di sini dan menghargai masukan Anda.
DanAbdn

Jawaban:

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

atau menggunakan dekorator HostListener :

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

Didukung target global window, documentdan body.

Sampai https://github.com/angular/angular/issues/13248 diimplementasikan di Angular, kinerja lebih baik untuk berlangganan acara DOM secara imperatif dan menggunakan RXJS untuk mengurangi jumlah acara seperti yang ditunjukkan dalam beberapa jawaban lain.

Günter Zöchbauer
sumber
15
Apakah ada dokumentasi tentang sintaks yang Anda gunakan: window: resize ?
Clement
3
Persis. Anda dapat menggunakan document,, windowdan body github.com/angular/angular/blob/…
Günter Zöchbauer
5
jawaban sempurna .. saya percaya @HostListener adalah cara yang lebih bersih :) tetapi pastikan untuk mengimpor HostListener terlebih dahulu menggunakanimport { Component, OnInit, HostListener } from '@angular/core';
Gaurav Sharma
4
Kiat cepat: Jika ingin memicu pada pemuatan pertama juga, terapkan ngAfterViewInit dari @ angular / core. angular.io/api/core/AfterViewInit
Zymotik
7
Namun, tentu saja, bagi mereka yang ingin tahu cara kerja HostListener dengan debounceTime, ikuti tautan di bawah ini plnkr.co/edit/3J0dcDaLTJBxkzo8Akyg?p=preview
jcdsr
65

@ Günter jawabannya benar. Saya hanya ingin mengusulkan metode lain.

Anda juga bisa menambahkan host-binding di dalam @Component()-decorator. Anda dapat menempatkan acara dan panggilan fungsi yang diinginkan di properti host-metadata seperti:

@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
   }
}
John
sumber
2
Saya sudah mencoba setiap metode pada halaman ini dan sepertinya tidak ada yang berhasil. Apakah ada dokumentasi resmi tentang ini?
Tomat
bagaimana ketinggian viewport diperoleh pada beban?
Giridhar Karnik
@ GiridharKarnik, sudahkah Anda mencoba melakukan bagian window.innerWidthdalam ngOnInit, atau ngAfterViewInitmetode?
John
@ Tomat Referensi-API dapat ditemukan di sini. Banyak referensi yang di-autogenerasi (saya kira), dan kekurangan contoh atau penjelasan terperinci. Beberapa referensi api memiliki banyak contoh. Saya tidak dapat menemukan contoh nyata dari dokumen tentang ini. Mungkin disembunyikan di suatu tempat: P
John
1
di sini adalah referensi bagaimana penggunaannya
Anand Rockzz
52

Saya tahu ini sudah lama ditanyakan, tetapi ada cara yang lebih baik untuk melakukan ini sekarang! Saya tidak yakin apakah ada yang akan melihat jawaban ini. Jelas impor Anda:

import { fromEvent, Observable, Subscription } from "rxjs";

Kemudian di komponen Anda:

resizeObservable$: Observable<Event>
resizeSubscription$: Subscription

ngOnInit() {
    this.resizeObservable$ = fromEvent(window, 'resize')
    this.resizeSubscription$ = this.resizeObservable$.subscribe( evt => {
      console.log('event: ', evt)
    })
}

Maka pastikan untuk berhenti berlangganan saat menghancurkan!

ngOnDestroy() {
    this.resizeSubscription$.unsubscribe()
}
Chris Stanley
sumber
Satu-satunya cara yang berhasil bagi saya. Terima kasih!! :-) ... Saya baru saja menyesuaikan impor Anda. Mungkin rxjs saya lebih baru:import { fromEvent, Observable,Subscription } from "rxjs";
Jette
Di mana saya dapat menambahkan debounce (1000) di ini?
Deepak Thomas
3
Maaf atas keterlambatan balasan: untuk menambahkan debounce, Anda ingin menggunakanthis.resizeSubscription$ = this.resizeObservable$.pipe(debounceTime(1000)).subscribe( evt => { console.log('event: ', evt) })
Chris Stanley
41

Cara yang benar untuk melakukan ini adalah dengan memanfaatkan kelas EventManager untuk mengikat acara. Ini memungkinkan kode Anda berfungsi di platform alternatif, misalnya rendering sisi server dengan 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);
  }
}

Penggunaan dalam suatu komponen sesederhana menambahkan layanan ini sebagai penyedia ke app.module Anda dan kemudian mengimpornya dalam konstruktor komponen.

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();
    }
  }
}
cgatian
sumber
Sejauh ini saya tidak pernah memecat ponsel. Bagaimana Anda mendapatkan ukuran jendela awal dengan pendekatan ini?
user3170530
Seluler tidak memiliki windowobjek, sama seperti server tidak memiliki window. Saya tidak terbiasa dengan konfigurasi seluler yang berbeda tetapi Anda harus dapat dengan mudah mengadaptasi kode di atas untuk mengikat ke pendengar acara global yang benar
cgatian
@cgatian Saya seorang pemula tapi ini sepertinya jawaban yang tepat. Sayangnya saya tidak beruntung membuat langganan saya Masuk komponen. Bisakah Anda menambahkan jawaban bagaimana cara berlangganan ini dalam suatu komponen sehingga orang dapat melihat pembaruan?
Matthew Harwood
@cgatian saya akan membuat plunker tapi ini sepertinya tidak berhasil. Filter dalam layanan ini tampak aneh tho stackoverflow.com/q/46397531/1191635
Matthew Harwood
3
@cgatian Mobile does not have a window object.... mengapa menurut Anda browser seluler tidak memiliki objek jendela?
Drenai
31

Ini cara yang lebih baik untuk melakukannya. Berdasarkan jawaban Birowsky .

Langkah 1: Buat angular servicedengan RxJS 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
    };
};

Langkah 2: Suntikkan hal di atas servicedan berlangganan ke salah satu yang Observablesdibuat dalam layanan di mana pun Anda ingin menerima acara mengubah ukuran jendela.

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

}

Pemahaman yang baik tentang Pemrograman Reaktif akan selalu membantu dalam mengatasi masalah yang sulit. Semoga ini bisa membantu seseorang.

Giridhar Karnik
sumber
Saya percaya ini adalah kesalahan: this.height $ = (windowSize $ .pluck ('height') sebagai Observable <number>) .distinctUntilChanged (); Observable <number>) .distinctUntilChanged (); Sepertinya Anda ditempelkan di
differUntilChanged
Saya tidak mengerti Anda, tolong sebutkan.
Giridhar Karnik
Deteksi perubahan tidak akan diaktifkan saat Anda melakukan acara ini di luar Angular, yakin itulah yang ia maksud.
Mark Pieszak - Trilon.io
1
Saya memiliki kesalahan mengatakan 'memetik' tidak ada pada tipe BehaviorSubject. Mengubah kode ke this.height $ = windowSize $ .map (x => x.height) bekerja untuk saya.
Matt Sugden
@GiridharKamik Bisakah Anda memberikan solusi yang akan berlangganan lebar & tinggi pada saat yang sama, yang bisa kita berlangganan baik lebar, tinggi dalam 1 berlangganan sederhana
ghiscoding
11

Saya tidak melihat orang berbicara tentang MediaMatcherdari angular/cdk.

Anda dapat mendefinisikan MediaQuery dan melampirkan pendengar ke dalamnya - lalu di mana pun di templat Anda (atau ts), Anda dapat meminta hal-hal jika Pencocokan cocok. Contoh Langsung

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

sumber: https://material.angular.io/components/sidenav/overview

Stavm
sumber
6

Dengan asumsi bahwa <600px berarti ponsel untuk Anda, Anda dapat menggunakan ini yang dapat diamati dan berlangganan:

Pertama kita perlu ukuran jendela saat ini. Jadi kami membuat diamati yang hanya memancarkan nilai tunggal: ukuran jendela saat ini.

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

Maka kita perlu membuat yang lain yang bisa diamati, sehingga kita tahu kapan ukuran jendela diubah. Untuk ini, kita dapat menggunakan operator "fromEvent". Untuk mempelajari lebih lanjut tentang operator rxjs, silakan kunjungi: rxjs

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

Gabungkan kedua aliran ini untuk menerima pengamatan kami:

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

Sekarang Anda dapat berlangganan seperti ini:

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

Ingatlah untuk berhenti berlangganan :)

Flosut Mözil
sumber
5

Ada layanan ViewportRuler di CDK sudut. Ini berjalan di luar zona, dan bekerja dengan rendering sisi server juga.

Totati
sumber
2
ini harus menjadi jawaban yang diterima. Semua yang diperlukan + ini adalah fungsi bawaan bawaan CDK.
Deniss M.
3

Berdasarkan solusi dari @cgatian saya akan menyarankan penyederhanaan berikut:

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

Pemakaian:

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) { }
}
Johannes Hoppe
sumber
Saya menemukan ini sebagai solusi terbaik, namun, ini hanya berfungsi ketika jendela diubah ukurannya, tetapi tidak ketika memuat atau ketika router berubah. Tahukah Anda, bagaimana cara menerapkan perubahan, memuat ulang atau memuat perute?
jcdsr
Anda dapat menambahkan fungsi ke layanan dan memicunya di komponen @jcdsr: getScreenSize () {this.onResize $ .emit ({width: window.innerWidth, height: window.innerHeight}); }
DanielWaw
3

Ini bukan jawaban yang tepat untuk pertanyaan tersebut tetapi dapat membantu seseorang yang perlu mendeteksi perubahan ukuran pada elemen apa pun.

Saya telah membuat perpustakaan yang menambahkan resizedacara ke elemen apa pun - Angular Resize Event .

Ini digunakan secara internal ResizeSensordari Query Elemen CSS .

Contoh penggunaan

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;
  }
}
Martin Volek
sumber
jika Anda ingin mendeteksi ukuran jendela maka Angular Material Breakpoint Observer sudah menangani material.angular.io/cdk/layout/overview
Darren Street
Tapi ini tidak mendeteksi hanya ukuran jendela, tetapi setiap elemen mengubah ukuran.
Martin Volek
2

Saya menulis lib ini untuk menemukan perubahan ukuran batas komponen sekali (ukuran) di Angular, semoga ini membantu orang lain. Anda dapat meletakkannya di komponen root, akan melakukan hal yang sama seperti mengubah ukuran jendela.

Langkah 1: Impor modul

import { BoundSensorModule } from 'angular-bound-sensor';

@NgModule({
  (...)
  imports: [
    BoundSensorModule,
  ],
})
export class AppModule { }

Langkah 2: Tambahkan arahan seperti di bawah ini

<simple-component boundSensor></simple-component>

Langkah 3: Menerima detail ukuran batas

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

@Component({
  selector: 'simple-component'
  (...)
})
class SimpleComponent {
  @HostListener('resize', ['$event'])
  onResize(event) {
    console.log(event.detail);
  }
}
PRAISER
sumber
1

Pada Angular2 (2.1.0) saya menggunakan ngZone untuk menangkap acara perubahan layar.

Lihatlah contohnya:

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

Semoga bantuan ini!

Anh Hoang
sumber
1

Kode di bawah ini memungkinkan mengamati perubahan ukuran untuk div yang diberikan di Angular

<div #observed-div>
</div>

kemudian di Komponen:

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;
}
abedfar
sumber
Saya ingin mengubah varibale dari penghitung = 6 untuk menghitung = 0 pada 767px lebar-maksimum, Bagaimana saya melakukannya?
Thanveer Shah
0

semua solusi tidak bekerja dengan sisi-server atau universal angular

jcdsr
sumber
0

Saya memeriksa sebagian besar jawaban ini. kemudian memutuskan untuk memeriksa dokumentasi Angular tentang Tata Letak .

Angular memiliki Pengamat sendiri untuk mendeteksi ukuran yang berbeda dan mudah diterapkan ke dalam komponen atau Layanan.

contoh sederhana adalah:

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

semoga membantu

Mj Jameel
sumber