我想基于窗口重新调整大小事件(在加载时动态地)执行一些任务。
目前我的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);
}
}
如何从此事件对象中检索宽度和高度?
感谢。
答案 0 :(得分:391)
<div (window:resize)="onResize($event)"
onResize(event) {
event.target.innerWidth;
}
或
@HostListener('window:resize', ['$event'])
onResize(event) {
event.target.innerWidth;
}
支持的全球目标为window
,document
和body
。
在Angular中实现https://github.com/angular/angular/issues/13248之前,性能最好是必须订阅DOM事件,并使用RXJS来减少事件数量,如其他一些答案中所示。
答案 1 :(得分:53)
@Günter的回答是正确的。我只是想提出另一种方法。
您还可以在 $scope.save = function (modalstate, id) {
var url = $scope.url,
data = $scope.formdata;
//append id to the URL if the form is in edit mode
if (modalstate === 'edit') {
url += "/" + id;
data = angular.merge(data, {_method: 'PATCH'});
}
if (!$("#myform").isValid()) {
return false;
} else {
console.log('request');
$http({
method: "POST",
url: url,
data: data,
headers: {'Content-Type': undefined},
transformRequest: function (data) {
console.log(angular.toJson(data));
var formData = new FormData();
formData.append("data", [angular.toJson(data)]);
if (typeof (data.logo) != "undefined")
{
formData.append("file", data.logo);
}
console.log(formData);
return formData;
},
}).success(function (response) {
console.log(response);
// location.reload();
}).error(function (response) {
console.log(response);
alert('This is embarassing. An error has occured. Please check the log for details');
});
}
- 装饰器中添加主机绑定。您可以将事件和所需的函数调用放在host-metadata-property中,如下所示:
@Component()
答案 2 :(得分:33)
执行此操作的正确方法是使用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();
}
}
}
答案 3 :(得分:28)
这是一种更好的方法。基于Birowsky's回答。
第1步:使用RxJS Observables创建angular service
。
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
});
}
}
对反应式编程的充分理解将始终有助于克服困难问题。希望这有助于某人。
答案 4 :(得分:24)
我知道这是很久以前问过的,但是现在有一种更好的方法!我不确定是否有人会看到这个答案。显然是您的进口货:
import { fromEvent } from "rxjs/observable/fromEvent";
import { Observable } from "rxjs/Observable";
import { Subscription } from "rxjs/Subscription";
然后在您的组件中:
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 :(得分:8)
我还没有看到有人在谈论 exclude 'LICENSE'
}
的{{1}}。
您可以定义MediaQuery并将侦听器附加到它 - 然后在模板(或ts)的任何位置,如果匹配匹配,您可以调用内容。 LiveExample
<强> App.Component.ts 强>
MediaMatcher
<强> App.Component.Html 强>
angular/cdk
<强> App.Component.css 强>
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);
}
}
答案 6 :(得分:6)
假设&lt; 600px意味着移动给你,你可以使用这个observable并订阅它:
首先我们需要当前的窗口大小。因此,我们创建一个只发出单个值的observable:当前窗口大小。
initial$ = Observable.of(window.innerWidth > 599 ? false : true);
然后我们需要创建另一个observable,以便我们知道窗口大小何时被更改。为此,我们可以使用&#34; fromEvent&#34;运营商。要了解有关rxjs`s运营商的更多信息,请访问: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); });
请记得取消订阅:)
答案 7 :(得分:3)
根据@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) { }
}
答案 8 :(得分:3)
这不是问题的答案,但它可以帮助需要检测任何元素大小变化的人。
我创建了一个库,可以将resized
事件添加到任何元素 - Angular Resize Event 。
它在内部使用CSS Element Queries中的ResizeSensor
。
<div (resized)="onResized($event)"></div>
@Component({...})
class MyComponent {
width: number;
height: number;
onResized(event: ResizedEvent): void {
this.width = event.newWidth;
this.height = event.newHeight;
}
}
答案 9 :(得分:2)
我写了this lib来查找Angular中的组件边界大小更改(调整大小),这可能有助于其他人。您可以将它放在根组件上,与窗口大小调整一样。
第1步:导入模块
<div class="recipe_create_form_input_lable">Ing</div>
<div class="ingredients-list">
{{#each ing}}
<div class="ingredients-div" id="ing_parent_{{@index}}">
<div class="ing-list-box-left">
<input type="text" value="{{this}}" placeholder="Ing " class="ree-create-text_box_rectangle ingredient_input" id="ing_{{@index}}"> <span class="timeLable"></span>
</div>
<div class="ings-list-box-right">
<button type="button" class="btn btn-default delete-ing-btn" style="margin-left : 5px;">
<!-- <img src="/images/remove-copy-2.svg" style="width:30px;"/> -->
<label style="width:30px;height: 18px;">x</label>
</button>
</div>
</div>
{{/each}}
</div>
{{#each stepList}}
<div class="step-div" id="step_{{@index}}">
<div class="step-list-box-left">
<div class="rec_create_form_input_lable stepLabel">Step {{getStepNo(@index)}}</div>
<div value="{{this}}" id="step_input_{{@index}}" name="step" class="rec-create-text_box_rectangle stepbox step_input" contenteditable="true"></div>
</div>
<div class="step-list-box-right">
<button type="button" class="btn btn-default delete-step-btn" style="margin-left : 5px;">
<label style="width:30px;height: 18px;">x</label>
</button>
</div>
</div>
<div class="showbiz">
<div class="custom-input">
<div class="selectable-tags">
{{#each ing }}
<span style=" background: #E1ECF4;border: 1px dotted #39739d;" class="ingredients-tags"> {{this}} </span>
{{/each}}
</div> </div>
</div>
{{/each}}
<div>
第2步:添加如下指令
import { BoundSensorModule } from 'angular-bound-sensor';
@NgModule({
(...)
imports: [
BoundSensorModule,
],
})
export class AppModule { }
第3步:接收边界尺寸详情
<simple-component boundSensor></simple-component>
答案 10 :(得分:2)
我检查了大多数这些答案。然后决定查看Layout上的Angular文档。
Angular拥有自己的观察器,用于检测不同的大小,并且很容易将其实现到组件或服务中。
一个简单的例子是:
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();
}
});
}
}
希望有帮助
答案 11 :(得分:1)
在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 :(得分:1)
以下是最新版本的Rxjs对@GiridharKamik答案的更新。
import { Injectable } from '@angular/core';
import { Observable, BehaviorSubject, fromEvent } from 'rxjs';
import { pluck, distinctUntilChanged, map } from 'rxjs/operators';
@Injectable()
export class WindowService {
height$: Observable<number>;
constructor() {
const windowSize$ = new BehaviorSubject(getWindowSize());
this.height$ = windowSize$.pipe(pluck('height'), distinctUntilChanged());
fromEvent(window, 'resize').pipe(map(getWindowSize))
.subscribe(windowSize$);
}
}
function getWindowSize() {
return {
height: window.innerHeight
//you can sense other parameters here
};
};
答案 13 :(得分:0)
下面的代码可让您观察Angular中任何给定div的大小变化。
<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;
}
答案 14 :(得分:0)
在角度CDK中有一个ViewportRuler服务。它在区域之外运行,并且也可以与服务器端渲染一起使用。
答案 15 :(得分:0)
所有解决方案均不适用于服务器端或通用角度
答案 16 :(得分:0)
这是我创建的一个简单干净的解决方案,因此可以将其注入到多个组件中。
ResizeService.ts
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class ResizeService {
constructor() {
window.addEventListener('resize', (e) => {
this.onResize.next();
});
}
public onResize = new Subject();
}
使用中:
constructor(
private resizeService: ResizeService
) {
this.subscriptions.push(this.resizeService.onResize.subscribe(() => {
// Do stuff
}));
}
private subscriptions: Subscription[] = [];
答案 17 :(得分:0)
我所做的如下,很像 Johannes Hoppe 的建议:
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',
event => this.onResize$.emit({
width: event.target.innerWidth,
height: event.target.innerHeight
}));
}
getWindowSize(){
this.onResize$.emit({
width: window.innerWidth,
height: window.innerHeight
});
}
}
在 app.component.ts 中:
Import { ResizeService } from ".shared/services/resize.service"
import { Component } from "@angular/core"
@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent{
windowSize: {width: number, height: number};
constructor(private resizeService: ResizeService){
}
ngOnInit(){
this.resizeService.onResize$.subscribe((value) => {
this.windowSize = value;
});
this.resizeService.getWindowSize();
}
}
然后在你的 app.component.html 中:
<router-outlet *ngIf = "windowSize?.width > 1280 && windowSize?.height > 700; else errorComponent">
</router-outlet>
<ng-template #errorComponent>
<app-error-component></app-error-component>
</ng-template>