【问题标题】:Host binding throws ExpressionChanged error even when calling detectChanges即使在调用 detectChanges 时,主机绑定也会引发 ExpressionChanged 错误
【发布时间】:2019-08-26 20:50:18
【问题描述】:

查看以下 Stackblitz:https://stackblitz.com/edit/angular-psqzbo?file=src%2Fapp%2Fhello.component.ts

请注意,width 成员有两个绑定:一个在模板中,另一个是主机绑定。主机绑定现在被注释掉了。请注意,没有抛出 ExpressionChanged 错误 - 这是因为在我们更新 ngAfterViewInit 中的 width 之后调用了 this.cdr.detectChanges()

现在取消注释主机绑定。观察是否引发了 ExpressionChanged 错误。为什么?这些绑定有何不同?这是一个错误吗?

编辑:这不是链接问题的欺骗。我知道为什么这里需要detectChanges,我的问题是为什么它在主机绑定上不起作用。请重新阅读。

【问题讨论】:

  • 不,拜托,这不是骗子。请重新阅读这个问题,我担心它会被当作骗子关闭......
  • 对该问题的接受答案(将代码移动到ngOnInit)解决了您的示例中的问题,此外,问题上的解释提供了一个很好的问题演练。该解决方案不适合您的情况吗?
  • 不,这不适用于我的情况,因为 offsetWidth 仅在 ngAfterViewInit 中可用(然后视图已经合成)。视图尚未在 ngOnInit 或 ngAfterContentInit 中组合。
  • 我已经撤回了我的重复投票(因为你是正确的),很快就会写一个答案

标签: javascript angular


【解决方案1】:

发生此错误是因为您所做的更改使之前呈现的组件视图无效。

引用this documentation

Angular 的单向数据流规则禁止在视图组合后对其进行更新。这两个钩子都会在组件的视图合成后触发。

这对您的情况意味着什么:

当 Angular 首次渲染/组合该组件的视图时(之前的 ngAfterViewInit),元素的宽度被设置为初始值。此代码更改元素的宽度,从而导致视图发生变化。

我认为this example 使用背景颜色会使这一点更加明显。在渲染视图的第一遍中,颜色是red(您可以在屏幕上简单地看到它)。在您的情况下,第一次通过时未定义宽度绑定。

然后,ngAfterViewInit 会导致先前创建的视图无效,更改宽度或颜色,从而触发错误。我将此错误翻译为 Angular 说“我做了很多工作并做出了一个完美的视图,然后你做了一些让这项工作毫无价值的事情。你不应该这样做,因为它会打断我的一些性能优化/假设” .

这可以通过使用setTimeout 确保在ngAfterViewInit 方法完成运行后发生组件更改来解决。 Fixed example 或者通过将视图移动到 ngOnInit 来确保组件更改发生在视图呈现之前。


您可能会注意到我创建的示例中没有detectChanges。这是故意的,因为这是一个红鲱鱼,实际上与问题无关(尽管您正确地声明这是模板绑定工作所必需的)。当在您的示例中注释掉主机绑定时,不存在表达式问题,因为this.width 对组件的呈现视图没有影响

当绑定在模板中时没有问题,因为这会导致组件的内容发生变化——而不是组件自己的视图。


推测/我不完全理解的事情:

我相信这种行为归结为 Shadow DOM 与 Light DOM 的变化(我根据来自 this SO question 的信息进行猜测)。在ngAfterViewInit运行的时候,我相信Light DOM中已经有一个空标签<my-component></my-component>了(IE实际上在页面上)。更改子内容不会导致问题,因为此时它在页面上实际上并不存在,并且是 Shadow DOM 的一部分。但是,更改主机绑定会触发页面上的 real 元素(Light DOM 的一部分)的更改 - 因此会出现错误。

【讨论】:

  • @sir-thursday 这就是说“因为 Angular 生命周期以不同的步骤处理它们”的方式很长。对我来说已经晚了,但是如果您对我刚刚写的内容有疑问,我会在明天尝试回复。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-01-04
  • 1970-01-01
  • 1970-01-01
  • 2014-06-13
  • 2014-01-22
相关资源
最近更新 更多