Angular:修改iframe的[src]属性时如何触发旧页面的ngOnDestroy
原因说明
直接修改iframe的src属性、手动清空iframe文档内容,都属于浏览器层面的DOM操作,不会触发iframe内部Angular应用的ngOnDestroy生命周期钩子——Angular的组件销毁逻辑是框架内部调度的,浏览器不会主动调用。
可行解决方案
方案1:同域通信主动触发销毁(推荐,不破坏原有生命周期逻辑)
因为所有加载的都是内部同源链接,可以在子页面(iframe加载的Angular页面)的全局window对象上挂载手动销毁方法:
// 子页面组件代码 ngOnInit(): void { // 挂载全局销毁方法 (window as any).triggerNgDestroy = () => { this.ngOnDestroy(); }; } ngOnDestroy(): void { // 原有清理逻辑,比如清除定时器 if (this.intervalId) { clearInterval(this.intervalId); } }
父页面切换iframe地址之前,先调用该方法触发子页面销毁:
// 父页面切换幻灯片逻辑 const iframe = document.getElementById('iframeSlide') as HTMLIFrameElement; // 先触发旧页面的销毁逻辑 if (iframe.contentWindow && (iframe.contentWindow as any).triggerNgDestroy) { (iframe.contentWindow as any).triggerNgDestroy(); } // 再赋值新的页面地址 current.urlSafe = current.sanitizer.bypassSecurityTrustResourceUrl(current.slideUrls[current.index]);
方案2:重建iframe节点(无需修改子页面代码)
每次切换地址时直接删除旧的iframe DOM节点,再重新创建新的iframe插入原位置,旧iframe的整个执行上下文会被浏览器完全回收,内部定时器会自动清除:
- 先修改HTML,给iframe加一个固定父容器:
<!-- 原有iframe替换为如下结构 --> <div id="iframeContainer" style="width: 100%; height: 100%;"> <iframe width="100%" id="iframeSlide" height="100%" frameBorder="0" [src]="urlSafe"></iframe> </div>
- 切换地址的逻辑修改为:
const container = document.getElementById('iframeContainer'); // 移除旧iframe const oldIframe = document.getElementById('iframeSlide'); oldIframe && container.removeChild(oldIframe); // 创建新iframe const newIframe = document.createElement('iframe'); newIframe.id = 'iframeSlide'; newIframe.width = '100%'; newIframe.height = '100%'; newIframe.frameBorder = '0'; // 赋值新地址 const safeUrl = current.sanitizer.bypassSecurityTrustResourceUrl(current.slideUrls[current.index]); newIframe.src = safeUrl.changingThisBreaksApplicationSecurity; // 插入容器 container.appendChild(newIframe);
方案3:父页面直接清空子页面所有定时器
如果不想修改子页面也不想重建iframe,可以在切换地址前遍历清除子页面的所有定时器:
const iframe = document.getElementById('iframeSlide') as HTMLIFrameElement; const win = iframe.contentWindow as any; if (win) { // 获取当前最大的定时器ID,遍历清空所有定时器和延时器 const maxId = win.setTimeout(() => {}, 0); for (let i = 0; i <= maxId; i++) { win.clearInterval(i); win.clearTimeout(i); } } // 再设置新的urlSafe
内容的提问来源于stack exchange,提问作者Hien Nguyen
相关产品推荐
相关产品推荐

