【问题标题】:Angular SSR window resize eventAngular SSR 窗口调整大小事件
【发布时间】:2018-12-13 03:53:02
【问题描述】:

我正在尝试创建一个 Angular 服务,组件可以使用它来观察窗口调整大小事件。经过多次尝试,我终于发现这个解决方案效果最好https://stackoverflow.com/a/43833815

但是,在 SSR 中运行时似乎会报错。

TypeError: this.eventManager.addGlobalEventListener is not a function

经过多次尝试,这就是我所在的位置:

服务

import { Injectable, Inject, PLATFORM_ID } from '@angular/core';
import { EventManager } from '@angular/platform-browser';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';

@Injectable()
export class WindowService {
  private resizeSubject: Subject<Window>;

  constructor(
    @Inject(PLATFORM_ID) private eventManager: EventManager) { // Event is not defined without @Inject(PLATFORM_ID) 
      this.resizeSubject = new Subject();

      this.eventManager.addGlobalEventListener('window', 'resize', this.onResize.bind(this));
  }

  private onResize(event: UIEvent) {
    this.resizeSubject.next(<Window>event.target);
  }

  /**
   * Get an observerable for the window resize event
   * @returns   Return the window resize as an observable
   */
  get onResize$(): Observable<Window> {
    return this.resizeSubject.asObservable();
  }
}

组件

import { Component, ElementRef, Input, OnInit, Output, EventEmitter, OnDestroy } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { Subscription } from 'rxjs/Subscription';

import { WindowService } from '../../services/window.service';


@Component({
  selector: 'app-sidebar',
  templateUrl: './sidebar.component.html'
})

export class SidebarComponent implements OnInit, OnDestroy {
  element: HTMLElement;
  resizeSubscription: Subscription;

  constructor(
    private readonly el: ElementRef,
    private windowService: WindowService) {
      this.element = el.nativeElement;
  }

  ngOnInit(): void {
    const self = this;

    this.resizeSubscription = this.windowService.onResize$
      .debounceTime(100)
      .subscribe(function(windowObj) {
        if (windowObj.innerWidth >= 1024) {
          self.open();
        } else {
          self.close();
        }
      });
  }

  ngOnDestroy(): void {
    if (this.resizeSubscription) {
      this.resizeSubscription.unsubscribe();
    }
  }

  ...
}

绑定到窗口大小调整事件似乎是一种非常复杂的方法,但我还没有找到更好的方法来使用 Angular SRR。有推荐的方法吗?本质上,我需要在调整大小(以及加载)时检查窗口大小并相应地打开或关闭侧边栏。

【问题讨论】:

  • 是否有什么东西阻止您在服务window.onresize = ... 中使用以下语法?
  • @Ploppy 我不确定这会起作用,因为 Angular SSR 不知道“窗口”是什么?
  • 我没有仔细阅读并错过了 SSR 部分,但是,我认为你做得很好,你甚至对 observable 进行了去抖动。我没有看到任何不好的情况,但请等待更多人确认。
  • 你为什么不检查平台是否只添加事件处理程序,如果你是客户端?
  • @David 我尝试将 this.eventManager.addGlobalEventListener 包装在 isPlatform 检查中,然后加载服务器端正常,但是当它将状态传输到客户端时它会出错。我假设是因为此时 WindowService 构造函数已经初始化,并且 angular 不会重新初始化 globalEventListener。

标签: angular server-side-rendering


【解决方案1】:

您可以使用platformId编写不同的代码服务器和浏览器:

 constructor( @Inject(PLATFORM_ID) private platformId: Object, private eventManager: EventManager) {
      this.resizeSubject = new ReplaySubject();
    if (isPlatformBrowser(this.platformId)) {
      this.eventManager.addGlobalEventListener('window', 'resize', this.onResize.bind(this));
    }
  }

对于用户全局窗口、文档、事件写成:https://github.com/Angular-RU/angular-universal-starter/blob/6d1e980655a55b2e1651ac5d040aaff80bc8fe8c/server.ts#L13

【讨论】:

    【解决方案2】:
    <div (window:resize)="onResize($event)"
    

    方法:

    onResize(event) {
      event.target.innerWidth;
    }
    

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

    支持的全局目标是 windowdocumentbody

    【讨论】:

    • 这对 SSR 有效吗?如果多个组件采用这种方法,是否会因为未通过服务处理窗口大小调整而影响性能?
    • 另外,你会如何去抖动这个?
    猜你喜欢
    • 2014-04-06
    • 1970-01-01
    • 1970-01-01
    • 2010-10-13
    • 2017-04-26
    • 2016-06-02
    相关资源
    最近更新 更多