角度窗口调整大小事件

时间:2016-02-20 18:42:31

标签: javascript 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);
    }
}

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

感谢。

18 个答案:

答案 0 :(得分:391)

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

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

支持的全球目标为windowdocumentbody

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

}

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

答案 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

使用示例

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

答案 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>