Angular 通用 - 不应使用超时

Angular Universal - timeout should not be used

所以我一直在尝试将我的应用程序转换为 angular 通用,并且在大多数情况下都很好。 但是我之前读了一些"gotchas":https://github.com/onespeed-articles/angular-universal-gotchas

它建议我不应该使用 timeout 这很烦人,因为在 angularjs 中你用它来让东西在视图后触发已渲染,因此您可以确定元素的尺寸是否正确等。

我还读到它仍然存在于 angular 6 所以我有这个指令:

import { Directive, ElementRef, AfterViewInit, Input, HostListener } from '@angular/core';

@Directive({
  selector: '[pyb-button-group]'
})
export class ButtonGroupDirective implements AfterViewInit {
  @Input() className: string;

  @HostListener('window:resize', ['$event'])
  onResize() {
    let resize = this.resize;
    let element = this.element;
    let className = this.className;

    setTimeout(function () {
      resize(element, className);
    }, 500);
  }

  constructor(private element: ElementRef) {
  }

  ngAfterViewInit() {
    this.resize(this.element, this.className);
  }

  resize(nativeElement, className) {
    let elements = nativeElement.nativeElement.getElementsByClassName(className || 'btn-choice');
    let headerHeight = 0;

    for (var i = 0; i < elements.length; i++) {
      let element = elements[i];
      let header = element.getElementsByClassName('header');

      if (!header.length) return;

      header = header[0];
      header.style.height = 'auto'; // Reset when resizing the window

      let height = header.offsetHeight;
      if (height > headerHeight) headerHeight = height;
    }

    for (var i = 0; i < elements.length; i++) {
      let element = elements[i];
      let header = element.getElementsByClassName('header');

      if (!header.length) return;

      header = header[0];
      header.style.height = headerHeight + 'px';
    }
  }
}

当浏览器调整大小时,它会等待 0.5 秒,然后再尝试调整按钮组的大小。 如果这是不好的做法,我应该改用什么?

您希望该代码 运行 在浏览器中而不是在服务器中。您提供的 link 给出了解决方案:

 if (isPlatformBrowser(this.platformId)) {
      //your setTimeout here
  }

When the browser resizes, it waits for .5 of a second before it tries to resize the button group. If this is bad practice, what should I use instead?

您正在延迟 每个 调整大小事件。通常,您希望每 500 毫秒去抖并只处理一个事件。这可以使用 observable 来完成,但请确保在组件被销毁时取消订阅。

observableFromEvent(window, 'resize')
  .pipe(debounceTime(500))
  .subscribe(() => this.resize(this.element, this.className))

另外 @HostListener() 在服务器端呈现期间从不触发事件。服务器上没有 DOM 触发 window 调整大小事件。

  setTimeout(function () {
      resize(element, className);
  }, 500);

您在此处使用的 setTimeout 全局函数在 NodeJS 中具有不同的函数签名。当您 运行 Angular Universe 中的应用程序时,它 运行 在 NodeJS 内部生成 HTML ,然后再进入 Web 浏览器。 setTimeout returns Web 浏览器上的数字,但 returns NodeJS 中的资源句柄。

如果您打算 运行 在 Angular Universal 中使用您的应用程序,那么这意味着您正在编写与 Web 浏览器分离的源代码。这意味着没有直接操作 DOM,没有全局变量,也没有全局 window 变量。