动态创建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点击更换背景颜色或图片的实例代码
Jun 25 Javascript
jquery实现加载等待效果示例
Sep 25 Javascript
jQuery复制表单元素附源码分享效果演示
Sep 30 Javascript
Treegrid的动态加载实例代码
Apr 29 Javascript
Spring MVC中Ajax实现二级联动的简单实例
Jul 06 Javascript
Angular2表单自定义验证器的实现
Oct 19 Javascript
Vue.js -- 过滤器使用总结
Feb 18 Javascript
JS闭包可被利用的常见场景小结
Apr 09 Javascript
vue-router2.0 组件之间传参及获取动态参数的方法
Nov 10 Javascript
详解vue的diff算法原理
May 20 Javascript
解决vue v-for src 图片路径问题 404
Nov 12 Javascript
React如何使用axios请求数据并把数据渲染到组件
Aug 05 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
用PHP和ACCESS写聊天室(五)
2006/10/09 PHP
wordpress之wp-settings.php
2007/08/17 PHP
PHP n个不重复的随机数生成代码
2009/06/23 PHP
php set_magic_quotes_runtime() 函数过时解决方法
2010/07/08 PHP
第三章 php操作符与控制结构代码
2011/12/30 PHP
PHP实现加密文本文件并限制特定页面的存取的效果
2016/10/21 PHP
PHP中soap用法示例【SoapServer服务端与SoapClient客户端编写】
2018/12/25 PHP
图片连续滚动代码[兼容IE/firefox]
2009/06/11 Javascript
ExtJS 刷新后如何默认选中刷新前最后一次选中的节点
2014/04/03 Javascript
chrome下jq width()方法取值为0的解决方法
2014/05/26 Javascript
使用jQuery设置disabled属性与移除disabled属性
2014/08/21 Javascript
使用jQuery实现验证上传图片的格式与大小
2014/12/03 Javascript
JS模态窗口返回值兼容问题的完美解决方法
2016/05/28 Javascript
AngularJS 文件上传控件 ng-file-upload详解
2017/01/13 Javascript
使用jquery判断一个元素是否含有一个指定的类(class)实例
2017/02/12 Javascript
完美解决UI-Grid表格元素中多个空格显示为一个空格的问题
2017/04/25 Javascript
Vue.js列表渲染绑定jQuery插件的正确姿势
2017/06/29 jQuery
javaScript手机号码校验工具类PhoneUtils详解
2017/12/08 Javascript
基于Vue2.X的路由和钩子函数详解
2018/02/09 Javascript
Vue父子组建的简单通信之控制开关Switch的实现
2018/06/04 Javascript
详解写好JS条件语句的5条守则
2019/02/28 Javascript
详解Vue中的Props与Data细微差别
2020/03/02 Javascript
python对url格式解析的方法
2015/05/13 Python
Odoo中如何生成唯一不重复的序列号详解
2018/02/10 Python
Django 实现 Websocket 广播、点对点发送消息的代码
2020/06/03 Python
python代数式括号有效性检验示例代码
2020/10/04 Python
python爬取音频下载的示例代码
2020/10/19 Python
python 写一个文件分发小程序
2020/12/05 Python
俄罗斯韩国化妆品网上商店:Cosmasi.ru
2019/10/31 全球购物
药学专业大专生的自我评价
2013/12/12 职场文书
初中生期末考试的自我评价
2013/12/17 职场文书
销售辞职报告范文
2014/01/12 职场文书
成品库仓管员岗位职责
2014/04/06 职场文书
优秀团员事迹材料1500字
2014/08/31 职场文书
劳模事迹材料范文
2014/12/24 职场文书
先进基层党组织事迹材料
2014/12/25 职场文书