动态创建Angular组件实现popup弹窗功能


Posted in Javascript onSeptember 15, 2017

起步: 直接使用ngIf

把弹窗的DOM直接放在页面底下隐藏,通过ngIf这样的指令控制其显示。

改进: 封装成angular模块,通过服务控制其显示

直接使用ngIf的话,让人不爽的地方就在于不够通用,每个页面都得加DOM。改进的话可以把比较通用的一些DOM封装成组件,统一添加到全局页面中,并将显示的控制交给一个angular服务来控制其显示。

比如定义了两个组件(DialogComponent, AlertComponent),将他们都添加到AppComponent下,然后提供一个PopupService来控制组件的显示,并支持传递参数进去。

仅通过控制显示的方式仍不够通用且存在耦合

将弹窗组件封装然后使用服务来控制显示的方法看上去已经比较通用了,不过还存在两个尴尬的问题:

  1. 仍然需要在页面的某个地方放置一个弹窗组件,比如叫做PopupComponent,此组件负责渲染出默认隐藏的一些通用弹窗子组件,才能进行显示控制实现弹窗能力。
  2. 如果想要弹出一个自定义窗口的话就只能回到最上面另外写DOM放到需要弹出自定义弹窗的位置上,或者将自定义的标签通过innerHtml指令传入(富文本方式)。

由此可见这样的弹窗能力并没有做到非常通用,且必须手动放置弹窗插座(姑且这么叫)以致多了一处耦合。

动态创建弹窗

最理想的方式应该是: 在想要弹个窗口出来时直接一行代码把窗口弹出来,不用事先在哪里先把这个弹窗写好(或者说这一步不应该由弹窗控件的使用者来做,弹窗控件应该要自动完成这件事)。

而这一能力就涉及到angular的动态创建组件的能力了。

官网给出的用法

angular的官方文档中就有关于动态创建组件的用法。不过其使用的是ViewContainerRef服务,此服务提供了createComponent方法来在指定的视图容器下动态创建一个组件出来。

不过ViewContainerRef的尴尬点是只能在具体的指令、组件中使用,也就是说,必须告诉它打算在哪个地方创建新组建,这不还是需要实现创建好一个“弹窗插座”出来,才可以在这个“插座”中动态创建组件。

那有什么办法可以不给定视图容器而创建出组建来,通俗地讲问题就是: 不是在指令或者组件中创建组件,而是在服务中创建出组件,还要让这个组件显示到页面上去。

组建工厂——组件真正的创建者

在组件中创建组件的核心代码分两步:

创建组件工厂

let componentFactory = this.componentFactoryResolver.resolveComponentFactory(待创建组件);

把工厂提供给容器创建出组件

let componentRef = viewContainerRef.createComponent(componentFactory);

现在的问题在于,在服务中得不到viewContainerRef,工厂倒是能创建成功。

其实有工厂了已经足够了,查看componentFactory提供的成员里面包含了一个create方法,顾名思义这应该就是用来创建组件的了。

create方法有个必选参数类型为Injector,顾名思义就是注入器,即这个创建的组件打算注入些什么服务进去,暴力点直接写null也没问题。

直接使用工厂创建组件返回的同样是一个ComponentRef类型的引用,可见此时组件确实是创建出来了,但是还没有将其插入到视图中去。此时可以再暴力一点,直接用原生DOM操作插入到body标签的末尾去:

window.document.body.appendChild(
  this.getComponentRootNode(componentRef)
);
this.appRef.attachView(componentRef); // 注入ApplicationRef服务后使用
// ...
private getComponentRootNode(componentRef: ComponentRef<any>): HTMLElement {
  return (componentRef.hostView as EmbeddedViewRef<any>).rootNodes[0] as HTMLElement;
}
// ...

此办法是笔者从Material2的茫茫源代码中找到的,Google自己都直接这么插,那就放心使用了。这里不得不赞叹Material2中Dialog模块的实现,实在是有够复杂。

总结

本文主要在讲思路,扯到最后才开始要进入主题来动态创建组件,不过仅仅是创建出组件并添加到DOM中去还只是第一步,一个健壮的弹窗模块(Material2那样的)还得有一套完善的交互能力,比如弹出和关闭时的订阅和传值,这些就要通过注入服务到组件中来实现了,限于篇幅将在下一篇文章中回归实际实现一个通过动态创建组件实现的弹窗模块出来。

以上所述是小编给大家介绍的动态创建Angular组件实现popup弹窗功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
js/jQuery简单实现选项卡功能
Jan 02 Javascript
自定义刻度jQuery进度条及插件
Sep 02 Javascript
JavaScript前端开发之实现二进制读写操作
Nov 04 Javascript
javascript实现计时器的简单方法
Feb 21 Javascript
javascript如何创建对象
Aug 29 Javascript
jQuery图片前后对比插件beforeAfter用法示例【附demo源码下载】
Sep 20 Javascript
解决vue里碰到 $refs 的问题的方法
Jul 13 Javascript
基于D3.js实现时钟效果
Jul 17 Javascript
动态内存分配导致影响Javascript性能的问题
Dec 18 Javascript
微信小程序日历效果
Dec 29 Javascript
前端vue-cli项目中使用img图片和background背景图的几种方法
Nov 13 Javascript
原生javascript制作贪吃蛇小游戏的方法分析
Feb 26 Javascript
Vue2.0基于vue-cli+webpack Vuex的用法(实例讲解)
Sep 15 #Javascript
angular4模块中给标签添加背景图的实现方法
Sep 15 #Javascript
基于Vue生产环境部署详解
Sep 15 #Javascript
基于Vue单文件组件详解
Sep 15 #Javascript
json2.js 入门教程之使用方法与实例分析
Sep 14 #Javascript
php main 与 iframe 相互通讯类(js+php同域/跨域)
Sep 14 #Javascript
iframe与主框架跨域相互访问实现方法
Sep 14 #Javascript
You might like
《魔兽争霸3》重制版究竟重制了什么?玩家:这么糊弄真的好吗?
2020/05/04 魔兽争霸
PHP 引用文件技巧
2010/03/02 PHP
php设计模式 Delegation(委托模式)
2011/06/26 PHP
php输出含有“#”字符串的方法
2017/01/18 PHP
浅谈PHP的反射API
2017/02/26 PHP
PHP按一定比例压缩图片的方法
2018/10/12 PHP
PHP利用缓存处理用户注册时的邮箱验证,成功后用户数据存入数据库操作示例
2019/12/31 PHP
JS BASE64编码 window.atob(), window.btoa()
2021/03/09 Javascript
图片连续滚动代码[兼容IE/firefox]
2009/06/11 Javascript
基本jquery的控制tabs打开的数量的代码
2010/10/17 Javascript
使用隐藏的new来创建对象
2011/03/29 Javascript
不用构造函数(Constructor)new关键字也能实现JavaScript的面向对象
2013/01/11 Javascript
浅析js中取绝对值的2种方法
2013/07/09 Javascript
JQuery实现倒计时按钮具体方法
2013/11/14 Javascript
javascript 操作cookies详解及实例
2017/02/22 Javascript
js实现分页功能
2017/05/24 Javascript
JavaScript该如何学习 怎样轻松学习JavaScript
2017/06/12 Javascript
jquery使用iscorll实现上拉、下拉加载刷新
2017/10/26 jQuery
vue进入页面时滚动条始终在底部代码实例
2019/03/26 Javascript
原生js 实现表单验证功能
2021/02/08 Javascript
Python编程实现双击更新所有已安装python模块的方法
2017/06/05 Python
python3使用requests模块爬取页面内容的实战演练
2017/09/25 Python
python链接oracle数据库以及数据库的增删改查实例
2018/01/30 Python
python自动重试第三方包retrying模块的方法
2018/04/24 Python
Python之虚拟环境virtualenv,pipreqs生成项目依赖第三方包的方法
2019/07/23 Python
Python如何调用JS文件中的函数
2019/08/16 Python
numpy ndarray 按条件筛选数组,关联筛选的例子
2019/11/26 Python
python实现二分类和多分类的ROC曲线教程
2020/06/15 Python
浅谈CSS3动画的回调处理
2016/07/21 HTML / CSS
ONLY德国官方在线商店:购买时尚女装
2017/09/21 全球购物
英国最大的在线奢侈手表零售商:Jura Watches
2018/01/29 全球购物
优质服务口号
2014/06/11 职场文书
批评与自我批评发言稿
2014/10/15 职场文书
爱心捐款感谢信
2015/01/20 职场文书
大一学生个人总结
2015/02/15 职场文书
PostgreSQL怎么创建分区表详解
2022/06/25 PostgreSQL