Javascript 角度窗口调整大小事件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35527456/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 17:50:32  来源:igfitidea点击:

Angular window resize event

javascriptangular

提问by DanAbdn

I would like to perform some tasks based on the window re-size event (on load and dynamically).

我想根据窗口大小调整事件(加载和动态)执行一些任务。

Currently I have my DOM as follows:

目前我的 DOM 如下:

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

The event correctly fires

事件正确触发

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

How do I retrieve the Width and Height from this event object?

如何从此事件对象中检索宽度和高度?

Thanks.

谢谢。

回答by Günter Z?chbauer

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

or using the HostListener decorator:

或使用HostListener 装饰器

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

Supported global targets are window, document, and body.

支持的全球目标是windowdocumentbody

Until https://github.com/angular/angular/issues/13248is implemented in Angular it is better for performance to subscribe to DOM events imperatively and use RXJS to reduce the amount of events as shown in some of the other answers.

在 Angular 中实现https://github.com/angular/angular/issues/13248之前,最好是强制订阅 DOM 事件并使用 RXJS 来减少事件数量,如其他一些答案所示。

回答by John

@Günter's answer is correct. I just wanted to propose yet another method.

@Günter 的回答是正确的。我只是想提出另一种方法。

You could also add the host-binding inside the @Component()-decorator. You can put the event and desired function call in the host-metadata-property like so:

您还可以在@Component()-decorator 中添加主机绑定。您可以将事件和所需的函数调用放在主机元数据属性中,如下所示:

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

回答by Chris Stanley

I know this was asked a long time ago, but there is a better way to do this now! I'm not sure if anyone will see this answer though. Obviously your imports:

我知道很久以前就有人问过这个问题,但现在有更好的方法来做到这一点!我不确定是否有人会看到这个答案。显然你的进口:

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

Then in your component:

然后在您的组件中:

resizeObservable$: Observable<Event>
resizeSubscription$: Subscription

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

Then be sure to unsubscribe on destroy!

然后一定要在销毁时取消订阅!

ngOnDestroy() {
    this.resizeSubscription$.unsubscribe()
}

回答by cgatian

The correct way to do this is to utilize the EventManagerclass to bind the event. This allows your code to work in alternative platforms, for example server side rendering with Angular Universal.

正确的做法是利用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);
  }
}

Usage in a component is as simple as adding this service as a provider to your app.module and then importing it in the constructor of a component.

在组件中使用就像将此服务作为提供者添加到 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();
    }
  }
}

回答by Giridhar Karnik

Here is a better way to do it. Based on Birowsky'sanswer.

这是一个更好的方法。基于比罗斯基的回答。

Step 1: Create an angular servicewith RxJS Observables.

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

Step 2: Inject the above serviceand subscribe to any of the Observablescreated within the service wherever you would like to receive the window resize event.

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

}

A sound understanding of Reactive Programming will always help in overcoming difficult problems. Hope this helps someone.

对反应式编程的充分理解总是有助于克服困难的问题。希望这可以帮助某人。

回答by Stavm

I haven't seen anyone talking about MediaMatcherof angular/cdk.

我还没有看到任何人谈论MediaMatcherangular/cdk

You can define a MediaQuery and attach a listener to it - then anywhere on your template (or ts) you can invoke stuff if the Matcher is matched. LiveExample

您可以定义一个 MediaQuery 并为其附加一个侦听器 - 如果匹配器匹配,您可以在模板(或 ts)上的任何位置调用内容。 实例

App.Component.ts

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

应用组件.html

<div [class]="mobileQuery.matches ? 'text-red' : 'text-blue'"> I turn red on mobile mode 
</div>

App.Component.css

应用组件.css

.text-red { 
   color: red;
}

.text-blue {
   color: blue;
}

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

来源:https: //material.angular.io/components/sidenav/overview

回答by Flosut M?zil

Assuming that < 600px means mobile to you, you can use this observable and subscribe to it:

假设 < 600px 对你来说意味着移动,你可以使用这个 observable 并订阅它:

First we need the current window size. So we create an observable which only emits a single value: the current window size.

首先我们需要当前的窗口大小。所以我们创建了一个只发出一个值的 observable:当前窗口大小。

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

Then we need to create another observable, so that we know when the window size was changed. For this we can use the "fromEvent" operator. To learn more about rxjs`s operators please visit: rxjs

然后我们需要创建另一个 observable,以便我们知道窗口大小何时发生变化。为此,我们可以使用“fromEvent”运算符。要了解有关 rxjs 运算符的更多信息,请访问:rxjs

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

Merg these two streams to receive our observable:

合并这两个流以接收我们的 observable:

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

Now you can subscribe to it like this:

现在你可以像这样订阅它:

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

Remember to unsubscribe :)

记得退订:)

回答by Totati

There's a ViewportRulerservice in angular CDK. It runs outside of the zone, and works with server side rendering too.

angular CDK 中有一个ViewportRuler服务。它在区域之外运行,也适用于服务器端渲染。

回答by Johannes Hoppe

Based on the solution of @cgatian I would suggest the following simplification:

基于@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
      }));
  }
}

Usage:

用法:

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

回答by Martin Volek

This is not exactly answer for the question but it can help somebody who needs to detect size changes on any element.

这不是问题的确切答案,但它可以帮助需要检测任何元素的大小变化的人。

I have created a library that adds resizedevent to any element - Angular Resize Event.

我创建了一个resized向任何元素添加事件的库- Angular Resize Event

It internally uses ResizeSensorfrom CSS Element Queries.

它在内部使用ResizeSensorfrom CSS Element Queries

Example usage

示例用法

HTML

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