Angular событие изменения размера окна
Я хотел бы выполнить некоторые задачи на основе события изменения размера окна (при загрузке и динамическом).
В настоящее время у меня есть DOM следующим образом:
<div id="Harbour">
<div id="Port" (window:resize)="onResize($event)" >
<router-outlet></router-outlet>
</div>
</div>
Событие правильно срабатывает
export class AppComponent {
onResize(event) {
console.log(event);
}
}
Как получить ширину и высоту из этого объекта события?
Спасибо.
Ответы
Ответ 1
<div (window:resize)="onResize($event)"
onResize(event) {
event.target.innerWidth;
}
или же
@HostListener('window:resize', ['$event'])
onResize(event) {
event.target.innerWidth;
}
Поддерживаемые глобальные цели: window
, document
и body
.
До тех пор, пока https://github.com/angular/angular/issues/13248 не будет реализован в Angular, для производительности лучше обязательно подписываться на события DOM и использовать RXJS для уменьшения количества событий, как показано в некоторых других ответах.
Ответ 2
@Ответ Günter верен. Я просто хотел предложить еще один метод.
Вы также можете добавить привязку хоста внутри @Component()
-decorator. Вы можете поместить событие и желаемый вызов функции в свойство-metadata-хоста следующим образом:
@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
}
}
Ответ 3
Правильный способ сделать это - использовать класс EventManager для привязки события. Это позволяет вашему коду работать на альтернативных платформах, например, на стороне сервера с помощью 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);
}
}
Использование в компоненте так же просто, как добавление этой услуги в качестве поставщика к вашему модулю приложения, а затем импорт его в конструкторе компонента.
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();
}
}
}
Ответ 4
Я знаю, что это было задано давно, но есть лучший способ сделать это сейчас! Я не уверен, что кто-нибудь увидит этот ответ. Очевидно, ваш импорт:
import { fromEvent, Observable, Subscription } from "rxjs";
Тогда в вашем компоненте:
resizeObservable$: Observable<Event>
resizeSubscription$: Subscription
ngOnInit() {
this.resizeObservable$ = fromEvent(window, 'resize')
this.resizeSubscription$ = this.resizeObservable$.subscribe( evt => {
console.log('event: ', evt)
})
}
Тогда обязательно отмените подписку на уничтожение!
ngOnDestroy() {
this.resizeSubscription$.unsubscribe()
}
Ответ 5
Вот лучший способ сделать это. На основе ответа Бировского.
Шаг 1. Создайте angular service
с помощью 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
};
};
Шаг 2: Внесите вышеуказанные service
и подпишитесь на любой из Observables
, созданный в службе, где бы вы хотели получить событие изменения размера окна.
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
});
}
}
Хорошее понимание реактивного программирования всегда поможет преодолеть сложные проблемы. Надеюсь, это поможет кому-то.
Ответ 6
Я не видел, чтобы кто-нибудь говорил о MediaMatcher
angular/cdk
.
Вы можете определить MediaQuery и присоединить к нему слушателя - тогда в любом месте вашего шаблона (или ts) вы можете вызывать вещи, если совпадает Matcher. LiveExample
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;
}
источник: https://material.angular.io/components/sidenav/overview
Ответ 7
Предполагая, что <600px означает мобильный для вас, вы можете использовать это наблюдаемое и подписаться на него:
Сначала нам нужен текущий размер окна. Таким образом, мы создаем наблюдаемый, который испускает только одно значение: текущий размер окна.
initial$ = Observable.of(window.innerWidth > 599 ? false : true);
Затем нам нужно создать еще одно наблюдаемое, чтобы мы знали, когда был изменен размер окна. Для этого мы можем использовать оператор "fromEvent". Чтобы узнать больше о операторах rxjs, посетите: rxjs
resize$ = Observable.fromEvent(window, 'resize').map((event: any) => {
return event.target.innerWidth > 599 ? false : true;
});
Сверните эти два потока, чтобы получить наш наблюдаемый:
mobile$ = Observable.merge(this.resize$, this.initial$).distinctUntilChanged();
Теперь вы можете подписаться на него следующим образом:
mobile$.subscribe((event) => { console.log(event); });
Не забывайте отменять подписку :)
Ответ 8
Основываясь на решении @cgatian, я бы предложил следующее упрощение:
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
}));
}
}
Использование:
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) { }
}
Ответ 9
Это не совсем ответ на вопрос, но он может помочь кому-то, кто должен определять изменения размера для любого элемента.
Я создал библиотеку, которая добавляет resized
событие к любому элементу - событие с угловым изменением размера.
Он внутренне использует ResizeSensor
из запросов элементов CSS.
Пример использования
HTML
<div (resized)="onResized($event)"></div>
Машинопись
@Component({...})
class MyComponent {
width: number;
height: number;
onResized(event: ResizedEvent): void {
this.width = event.newWidth;
this.height = event.newHeight;
}
}
Ответ 10
Я написал эту библиотеку, чтобы найти один раз изменение размера границы раздела (изменение размера) в Angular, возможно, это поможет другим людям. Вы можете поместить его в корневой компонент, сделайте то же самое, что и изменение размера окна.
Шаг 1: Импортировать модуль
import { BoundSensorModule } from 'angular-bound-sensor';
@NgModule({
(...)
imports: [
BoundSensorModule,
],
})
export class AppModule { }
Шаг 2: Добавьте директиву, как показано ниже
<simple-component boundSensor></simple-component>
Шаг 3: Получить сведения о размере границы
import { HostListener } from '@angular/core';
@Component({
selector: 'simple-component'
(...)
})
class SimpleComponent {
@HostListener('resize', ['$event'])
onResize(event) {
console.log(event.detail);
}
}
Ответ 11
В Angular2 (2.1.0) Я использую ngZone для захвата события смены экрана.
Взгляните на пример:
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);
});
};
}
Я надеюсь, что эта помощь!
Ответ 12
Код ниже позволяет наблюдать за любым изменением размера для любого данного div в Angular.
<div #observed-div>
</div>
затем в компоненте:
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;
}
Ответ 13
Есть сервис ViewportRuler в угловых CDK. Он работает за пределами зоны и также работает с рендерингом на стороне сервера.