Angular Universal - 不应使用超时

3

我一直在尝试将我的应用程序转换为Angular Universal,并且大部分情况下都很好。

但是我之前读到了一些需要注意的事项: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秒。如果这是不好的做法,那么应该使用什么替代方法?
2个回答

8
您希望该代码在浏览器中运行,而不是在服务器上。您提供的链接给出了解决方案:
 if (isPlatformBrowser(this.platformId)) {
      //your setTimeout here
  }

3
当浏览器调整大小时,它会在尝试调整按钮组大小之前等待0.5秒。如果这是不好的做法,我应该使用什么代替?
您正在延迟每个调整大小事件。通常,您希望去抖动并处理每500毫秒内仅一个事件。可以使用可观察对象来完成此操作,但请确保在销毁组件时取消订阅。
observableFromEvent(window, 'resize')
  .pipe(debounceTime(500))
  .subscribe(() => this.resize(this.element, this.className))

另外,@HostListener() 在服务器端渲染期间不会触发事件。因为在服务器上没有DOM来触发窗口调整大小的事件。

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

在这里使用的全局函数setTimeout在NodeJS中具有不同的函数签名。当您在Angular Universe中运行应用程序时,它在传递到Web浏览器之前在NodeJS内部运行以生成HTML。在Web浏览器中,setTimeout返回一个数字,但在NodeJS中返回资源句柄。

如果要在Angular Universal中运行应用程序,则意味着您正在编写与Web浏览器分离的源代码。这意味着不能直接操作DOM、没有全局变量和全局window变量。


非常感谢你的回答,我一定会尝试实现你提出的建议。不过,关于@HostListener()我有一个问题。我没有意识到它在服务器端渲染时不会触发。有没有其他替代方案我应该使用呢? - undefined
@r3plica 你可以使用 @HostListener 和其他 Angular 功能。请记住,Angular Universal 只是在服务器上使用编译后的 Web 应用程序捆绑包预渲染 HTML。然后将该 HTML 发送到 Web 浏览器,并且 Angular 进行“水合”以将当前的 Angular 状态与已经渲染的 HTML 匹配。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接