3

我创建了一个 Angular 2 应用程序,其中包含一个组件,我试图将其 HTML 元素相对于另一个组件定位。为了计算准确的坐标,我需要知道浏览器呈现的我自己元素的宽度和高度。

window.getComputedStyle(this.elementRef.nativeElement)用来获取这些属性。我注意到,在呈现页面时,属性会不断变化,直到页面呈现完成。为了了解任何更改并调整位置,我检查了ngAfterViewChecked组件方法中的值。

但是,当渲染导致新的计算样式属性时,它似乎没有ngAfterViewChecked被调用,因为我发现我的钩子不再被调用,即使计算的样式属性仍在变化。我假设 Angular 框架并非旨在检测这种变化。

我的第一次尝试是实现ngDoCheck钩子,但似乎在一段时间后以及在计算的样式属性具有其最终值之前,也没有调用这个钩子。我假设我还没有完全理解这个钩子应该在什么时候被调用。

我终于发现,如果我在 中实现一个setTimeout函数ngAfterViewChecked,这会导致稍后再次调用同一个钩子,即使我只传递了一个虚拟函数,例如:

setTimeout(() => {}, 500);

但坦率地说,我不明白为什么会这样。有人可以向我解释一下 thesetTimeoutngAfterViewCheckedhook 之间的联系吗?

虽然这似乎是一个有点肮脏的解决方法:检测和处理计算样式属性变化的正确“角度”方法是什么?


代码摘录:

export class MyComponent implements OnInit, AfterViewChecked
{
  private cssWidth: number;
  private cssHeight: number;

  constructor(private elementRef: ElementRef, private renderer: Renderer2)
  {
  }

  ngAfterViewChecked()
  {
    console.log("ngAfterViewChecked");
    this.updateView();
  }

  public updateView()
  {
    const sizeX = parseFloat(window.getComputedStyle(this.elementRef.nativeElement).width) || 0;
    const sizeY = parseFloat(window.getComputedStyle(this.elementRef.nativeElement.height) || 0;

    if (sizeX === this.cssWidth && sizeY === this.cssHeight) {
      // no change
      return;
    }

    console.log("Change detected!");

    // TODO Does not work without this dummy timeout function (else no more changes detected) - why so??
    setTimeout(() => {}, 500);

    [.. doing the positioning here ..]
 }
4

3 回答 3

2

请参阅此处的顶部图以查看生命周期图。如果 doCheck 中的钩子不起作用,那么 AfterViewChecked 也将不起作用,因为 doCheck 会启动 AfterViewChecked。

每次异步进程完成时,都会发生另一轮 doCheck。这将调用 AfterViewChecked,然后调用您的 updateView 函数。SetTimout() 是一个异步进程。我怀疑上面的代码会按原样无限循环。

我相信您想要的是让您在此处显示的内容的父组件使用 ngAfterViewChecked() 并调用 updateView()。此处探讨了该主题。

使两个组件协同工作的 Angular 方法是拥有一个可以在子组件之间传达更改的父组件,因为父组件是可以看到子组件中发生的事件的上下文。

我个人使用的解决方案是一个 EventEmitter,在未显示的组件中,在 ngOnInit() 函数中。它会通知父母它已被初始化。然后,在父组件中,在发出的事件上发生一个函数调用,告诉子组件你在这里更新视图。

于 2017-04-27T13:46:12.270 回答
1

在 vanilla JavaScript 中,您可以使用:

突变观察者

并在进行 DOM 更改时触发您自己的功能。

MutationObserver 为开发人员提供了一种对 DOM 中的更改做出反应的方法。它旨在替代 DOM3 事件规范中定义的突变事件。

于 2017-04-27T13:21:41.707 回答
0

当渲染导致新的计算样式属性时,为什么不调用 ngAfterViewChecked?

Angular 框架不会检测 DOM 元素的计算样式的变化,至少当它们是由浏览器的渲染引擎引起的时不会。因此,ngAfterViewChecked在这种情况下不会调用钩子。

为什么使用 setTimeout 时会起作用?

正如 Michael Palmer 的回答中所解释的,setTimeoutAngular 意识到可能导致更改的异步过程的原因。因此,在ngAfterViewChecked执行超时功能后调用挂钩。Angular 不会尝试检查setTimeout函数中究竟做了什么,以及这是否会真正影响视图。显然,这将很难实现,并且可能不值得付出努力。相反,Angular 会调用该ngAfterViewChecked钩子,以防异步过程中发生了影响视图的事情。

聆听计算样式更改的 Angular 方法是什么?

setTimeout除了使用来观察 DOM 元素的计算样式的变化之外,似乎别无他法。

于 2017-05-12T10:46:02.540 回答