angular - modal弹窗的关闭行为深入
背景:
民康项目中,弹窗里有echarts图,需要在弹窗关闭时dispose掉echarts,在nzOnCancel的方法里进行dispose操作,正常在当前页面里打开关闭弹窗是可以触发nzOnCancel的,但是url栏里输入url跳转到其他菜单,nzOnCancel不会触发,这样就存在内存泄露的风险
前置介绍
简单提一下ng组件加载的方式
ng组件的加载分为两种,一种是正常的指令模板(html)的加载,一层层往下递归,直到加载完毕
另一种是动态创建组件,viewContainerRef.createComponent 可在viewRef加载单独的host组件,路由就是通过此方法动态加载组件的;也可以通过viewContainerRef.createEmbeddedView加载ng-template模版;销毁动态组件,执行viewContainerRef.的清空即可
项目中对弹窗的使用总结:
1、使用nz-modal,直接内部包裹内容

2、使用nz-modal,以template形式引用content,赋值给nzContent

3、以modalService的形式创建弹窗,也是以template形式引用content,赋值给nzContent

对于第一种情况,我们先引入angular里的内容投影的概念
https://angular.cn/guide/content-projection

对于组件指令包裹的内部元素,组件可以把他投影在ng-content的位置中,内容投影的生命周期和父组件保持一致,可以理解为内容投影就是前置介绍里正常的指令模版渲染,只有父组件销毁时,投影才会销毁。
所以此情况下当前页面关闭弹窗,由于父组件未销毁,并不会销毁内容投影,所以内部的组件销毁钩子也不会执行。
用户在历史中前进/后退时,modal的默认配置是会触发弹窗关闭的,只要弹窗关闭,那么nzAfterClose一定会触发。nzOnCancel只有在点击取消和X时会触发

在管理后台的路由复用模式下,不会销毁原页面的组件,用户在历史中前进/后退时会触发弹窗关闭(会触发nzAfterClose),但因父组件未销毁,内容投影也不会销毁(不会触发内容组件的destroy钩子)。
如果路由是正常模式,用户在历史中前进/后退时原页面正常销毁,所以内容投影正常销毁。
对于第二、三种情况,可以归为同一类,都是通过加载template模版,动态创建的,当前页面正常关闭弹窗时,会执行动态组件的销毁,所以内容组件的销毁钩子会执行。用户在历史中前进/后退,与路由是否复用无关,都会触发弹窗关闭(nzAfterClose),动态组件都会销毁(destroy钩子)
总结:
modal组件,首先modal的内容组件需要在组件内部的destroy做好自身的内存释放工作。如果需要modal在关闭时做释放定时器或内存的操作,考虑 用户在历史中前进/后退 的场景,需要同时在nzOnCancel和nzAfterClose同时做内存释放(需要考虑正常关闭弹窗时,nzOnCancel和nzAfterClose先后触发,重复释放是否会引发异常)

浙公网安备 33010602011771号