我想执行一些基于窗口重新大小事件(在加载和动态)的任务。
目前我的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);
}
}
我如何从这个事件对象检索宽度和高度?
谢谢。
正确的方法是利用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);
}
}
在组件中使用这个服务非常简单,只需将这个服务作为提供者添加到app.module中,然后在组件的构造函数中导入它。
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();
}
}
}
@Günter的答案是正确的。我只是想提出另一种方法。
你也可以在@Component()装饰器中添加主机绑定。你可以像这样把事件和所需的函数调用放在host-metadata-property中:
@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
}
}
<div (window:resize)="onResize($event)"
onResize(event) {
event.target.innerWidth;
}
或者使用HostListener装饰器:
@HostListener('window:resize', ['$event'])
onResize(event) {
event.target.innerWidth;
}
支持的全局目标有window、document和body。
在https://github.com/angular/angular/issues/13248在Angular中实现之前,强制订阅DOM事件并使用RXJS来减少事件的数量(如其他一些答案所示)会更好地提高性能。
我还没看到有人在谈论angular/cdk的MediaMatcher。
您可以定义一个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
基于@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) { }
}