使用 setTimeout 时 Angular4 ngAfterViewChecked 被多次调用

标签 angular

我有一个服务,我想在 View 完全呈现后调用它。我做了一些挖掘并找到了 Angular 生命周期。对我来说最好的方法似乎是 AfterViewChecked,所以我更新了我的 AppComponent 并添加了:

import { Component, OnInit, AfterViewChecked } from "@angular/core";
import { ActivatedRoute, Params } from "@angular/router";

import { ResultsService } from "./shared/results.service";
import { HeightService } from "./shared/height.service";

@Component({
  selector: 'bzRoot',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit, AfterViewChecked {

  constructor(
    private _activatedRoute: ActivatedRoute,
    private _resultsService: ResultsService,
    private _heightService: HeightService
  ) { }

  ngOnInit() {
    this._activatedRoute.queryParams.subscribe((params: Params) => this._resultsService.elq = params['elq']);
  }

  ngAfterViewChecked() {
    console.log('hi');
  }
}

当我运行我的应用程序时,我可以看到控制台中有 25 个“hi”实例。我不知道为什么这么多,但这不是问题所在。 我的方法是调用我创建的服务,该服务使用 postMessage 向父窗口发送消息。它看起来像这样:

import { Injectable } from '@angular/core';

@Injectable()
export class HeightService {

  constructor() { }

  public resize() {
    console.log('resizing');

    var body = document.body,
        html = document.documentElement;

    var height = Math.max( 
      body.scrollHeight, 
      body.offsetHeight, 
      body.clientHeight, 
      html.offsetHeight
    );

    setTimeout(function () {
      parent.postMessage(height, '*');
    }, 0);
  }
}

我的 ngAfterViewChecked 方法现在看起来像这样:

ngAfterViewChecked() {
  this._heightService.resize();
}

如果我注释掉 setTimeout 行,它会回到 25 次调用。 有谁知道为什么以及如何阻止它发生?

最佳答案

这是设计使然。 docs说:

ngAfterViewChecked()
Respond after Angular checks the component's views and child views. Called after the ngAfterViewInit and every subsequent ngAfterContentChecked(). A component-only hook.

你正在寻找 ngAfterViewInit() 钩子(Hook)

编辑:似乎 Angular 钩子(Hook)不是满足您需求的解决方案,您应该保存最后发送的高度值并仅在值更改时触发调整大小

import { Injectable } from '@angular/core';

@Injectable()
export class HeightService {

  lastHeightPosted = null;
  constructor() { }

  public resize() {
    console.log('resizing');

    var body = document.body,
        html = document.documentElement;

    var height = Math.max( 
      body.scrollHeight, 
      body.offsetHeight, 
      body.clientHeight, 
      html.offsetHeight
    );

    if ( lastHeightPosted !== height) {
        parent.postMessage(height, '*');
        lastHeightPosted = height;
    }
  }

  ngAfterViewChecked() {
     this._heightService.resize();
  }
}

关于使用 setTimeout 时 Angular4 ngAfterViewChecked 被多次调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48381875/

相关文章:

javascript - Materialise css 轮播在 Angular 中不起作用

javascript - Angular ReactiveForms FormArray removeAt 移除FormArray中的所有元素

angular - 通过重定向登录后,Firebase Datasnapshot Observable 未立即更新

angular - 如何在 Angular 分量中添加延迟?

angular - 如何使用 Angular Material 使 mat-sidenav-content 占据 100% 的高度

visual-studio - Npm angularjs 2 - 找不到 "angular/compiler"依赖项

angular - Angular 中 ViewContainerRef 类的 "detach"方法到底做了什么?

node.js - 将 Node 和 Angular 部署到 Heroku 错误

node.js - 使用 JWT Passport 的 NestJS 身份验证不起作用

angular - 如何在 Angular2 中注销时获取新实例/重新加载所有服务