在 Angular 组件中放置 JavaScript 监听函数的最佳位置是啥?

Posted

技术标签:

【中文标题】在 Angular 组件中放置 JavaScript 监听函数的最佳位置是啥?【英文标题】:What is the best place to put a JavaScript listening function in Angular component?在 Angular 组件中放置 JavaScript 监听函数的最佳位置是什么? 【发布时间】:2018-07-08 21:50:39 【问题描述】:

TL;DR:

我在 iFrame 内的 Angular 5 应用程序中渲染 BioDigital HumanAPI 解剖模型。我使用以下方法实例化 API 对象:

this.human = new HumanAPI(iFrameSrc);

有一个 API 函数 human.on(...) 可用于从 iFrame 中注册点击事件(例如从模型中选取对象等)。我需要这个功能才能随时收听事件。我进行对象实例化并将这个函数放在ngOnInit() 中并且它可以工作,但是当我更改iFrame 的源以呈现不同的模型时,这个函数停止工作。我应该把这个监听函数放在哪里,以便它的逻辑始终可用?

加长版:

我正在使用 BioDigital HumanAPI 开发一个 Angular 应用程序。这里的基本思想是 HumanAPI 提供了几个解剖模型,可以使用iFrame(例如here)在网络应用程序中呈现这些模型。这个iFramesrc 是一个链接,类似于:

https://human.biodigital.com/widget?m=congestive_heart_failure

因为我希望我的 Angular 应用程序的用户能够查看多个这样的模型,所以我有一个这些 URL 的列表,并根据用户的选择,我使用一个函数更新 iFramesrc updateFrameSrc 代码如下:

iframeSrc: SafeUrl;
this.iframeSrc = this.sanitizer.bypassSecurityTrustResourceUrl(newUrl);

最后(问题来了,请和我在一起),为了在iFrame 本身内操作和注册不同的点击事件和用户与模型的交互,我们制作了一个这样的 HumanAPI 对象:

this.human = new HumanAPI(iFrameID);

这让我们可以使用像human.on('scene.picked') 这样的API 事件监听器函数来注册和保存点击事件(如我上面引用的示例所示)。所有这些都运行良好。

问题是,由于我在ngOnInit() 函数中初始化了human 对象并将human.on('scene.picked') 函数放在那里,所以在iFrame 源更改后我无法注册点击事件。据我了解,ngOnInit() 仅在组件首次初始化时调用一次,所以 可能 更新iFrame 源后human.on 的监听逻辑不可用?我尝试将逻辑放在不同的生命周期挂钩中,但它不起作用。

我目前的解决方法是在更新 iFrame 源后重新调用 ngOnInit() 函数,它就是这样工作的,但我认为这违反了标准生命周期管理实践。

我的问题是:

是否可以从组件逻辑中重新调用ngOnInit() 函数? 如果不是,我应该在哪里放置一个 javascript API 函数,该函数始终监听来自 iFrame 的点击事件,即使在 iFrame 的源已更改之后?

【问题讨论】:

为什么你不能把你需要的两行从 ngOnInit() 移到一个单独的函数中,并在 ngOnInit 和你的 updateFrameSrc 函数中调用该函数? @AbrahamAl-Dabbagh 好的,这毕竟是答案。我曾尝试过这种方式,但在更新iFrame 源后忘记再次初始化human 对象。请将此添加为答案,以便我接受! 【参考方案1】:

如果您正在寻找接近实时的数据,您会希望这发生在 NgOnChanges 生命周期挂钩中。请注意,这很昂贵。

如果可以接受稍微少一点的“接近实时”,我建议在组件初始化 NgOnInit 时连接一个快速延迟主题 Observable.Interval(500)(同样,但稍微便宜一些)。

请不要通过重新调用 ngOnInit 来绕过钩子。

如果您还有其他问题,请告诉我。

【讨论】:

我尝试使用 ngOnChanges() 进行此操作,但正如您所说,这对我的应用程序来说非常昂贵。问题是,只要我不更改 iFrame 源并且不使用延迟或某种强制侦听事件(例如在每个 mouseDown 事件上)。召回 ngOnInit() 也可以,所以我想可能也存在一些更便宜的解决方法。 我刚刚通过在 NgOnInit 中引导一个周期性任务 (Observable.Interval) 做了类似的事情。它会起作用,并且对于大多数用例,DOM 将呈现足够快的速度,以至于操作员/用户不会感觉到将其放入 ngOnChanges 中的任何延迟。请不要回忆 ngOnInit。它会导致可能不会立即显现出来的问题。【参考方案2】:

正如之前评论中所建议的,您可以将ngOnInit() 中的代码移动到一个单独的函数中,然后从ngOnInit() 以及您的更新函数中调用该函数。

在更新iFrame 源时,不要忘记在该函数中重新初始化HumanAPIhuman 对象。

应避免重新调用ngOnInit(),因为它会绕过@iHazCode 提到的可接受的生命周期挂钩功能。

【讨论】:

以上是关于在 Angular 组件中放置 JavaScript 监听函数的最佳位置是啥?的主要内容,如果未能解决你的问题,请参考以下文章

不能在 Angular 构造函数或 OnInit 中放置断点

如何在 Angular Material 的对话框中放置图像?

在 Vue.js 组件中放置 PayPal 按钮

如何在我的 ag-grid 单元格中放置一个 react jsx 组件

Angular ngx-mat-select-search 自定义组件

Angular的内置模块