起步: 直接使用ngIf
把弹窗的DOM直接放在页面底下隐藏,通过ngIf这样的指令控制其显示。
改进: 封装成angular模块,通过服务控制其显示
直接使用ngIf的话,让人不爽的地方就在于不够通用,每个页面都得加DOM。改进的话可以把比较通用的一些DOM封装成组件,统一添加到全局页面中,并将显示的控制交给一个angular服务来控制其显示。
比如定义了两个组件(DialogComponent, AlertComponent),将他们都添加到AppComponent下,然后提供一个PopupService来控制组件的显示,并支持传递参数进去。
仅通过控制显示的方式仍不够通用且存在耦合
将弹窗组件封装然后使用服务来控制显示的方法看上去已经比较通用了,不过还存在两个尴尬的问题:
由此可见这样的弹窗能力并没有做到非常通用,且必须手动放置弹窗插座(姑且这么叫)以致多了一处耦合。
动态创建弹窗
最理想的方式应该是: 在想要弹个窗口出来时直接一行代码把窗口弹出来,不用事先在哪里先把这个弹窗写好(或者说这一步不应该由弹窗控件的使用者来做,弹窗控件应该要自动完成这件事)。
而这一能力就涉及到angular的动态创建组件的能力了。
官网给出的用法
angular的官方文档中就有关于动态创建组件的用法。不过其使用的是ViewContainerRef服务,此服务提供了createComponent方法来在指定的视图容器下动态创建一个组件出来。
不过ViewContainerRef的尴尬点是只能在具体的指令、组件中使用,也就是说,必须告诉它打算在哪个地方创建新组建,这不还是需要实现创建好一个“弹窗插座”出来,才可以在这个“插座”中动态创建组件。
那有什么办法可以不给定视图容器而创建出组建来,通俗地讲问题就是: 不是在指令或者组件中创建组件,而是在服务中创建出组件,还要让这个组件显示到页面上去。
组建工厂——组件真正的创建者
在组件中创建组件的核心代码分两步:
创建组件工厂
let componentFactory = this.componentFactoryResolver.resolveComponentFactory(待创建组件);
把工厂提供给容器创建出组件
let componentRef = viewContainerRef.createComponent(componentFactory);
现在的问题在于,在服务中得不到viewContainerRef,工厂倒是能创建成功。
新闻热点
疑难解答
图片精选