动态创建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 相关文章推荐
IE与Firefox下javascript getyear年份的兼容性写法
Dec 20 Javascript
javascript页面渲染速度测试脚本分享
Apr 15 Javascript
jquery新的绑定事件机制on方法的使用方法
Apr 15 Javascript
jQuery打印图片pdf、txt示例代码
Jul 22 Javascript
AngularJS控制器controller正确的通信的方法
Jan 25 Javascript
jQuery 3.0 的 setter和getter 模式详解
Jul 11 Javascript
jquery横向纵向鼠标滚轮全屏切换
Feb 27 Javascript
详解JS函数stack size计算方法
Jun 18 Javascript
通过实例解析js简易模块加载器
Jun 17 Javascript
更优雅的微信小程序骨架屏实现详解
Aug 07 Javascript
node+multer实现图片上传的示例代码
Feb 18 Javascript
JS实现audio音频剪裁剪切复制播放与上传(步骤详解)
Jul 28 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与C#的值类型指向区别的详解
2013/05/21 PHP
ThinkPHP模版中导入CSS和JS文件的方法
2014/11/29 PHP
ExtJS 2.0实用简明教程 之Ext类库简介
2009/04/29 Javascript
Jquery Ajax学习实例7 Ajax所有过程事件分析示例
2010/03/23 Javascript
基于jquery打造的百分比动态色彩条插件
2012/09/19 Javascript
js跨浏览器实现将字符串转化为xml对象的方法
2013/09/25 Javascript
重写document.write实现无阻塞加载js广告(补充)
2014/12/12 Javascript
javascript实现下班倒计时效果的方法(可桌面通知)
2015/07/10 Javascript
Jquery简单分页实现方法
2015/07/24 Javascript
js实现input框文字动态变换显示效果
2015/08/19 Javascript
JS实现在状态栏显示打字效果完整实例
2015/11/02 Javascript
JavaScript驾驭网页-CSS与DOM
2016/03/24 Javascript
[原创]SyntaxHighlighter自动识别并加载脚本语言
2017/02/07 Javascript
Vue.js 中的 $watch使用方法
2017/05/25 Javascript
vue中七牛插件使用的实例代码
2017/07/28 Javascript
vue.js todolist实现代码
2017/10/29 Javascript
React学习笔记之高阶组件应用
2018/06/02 Javascript
vue-cli安装使用流程步骤详解
2018/11/08 Javascript
详解nodejs解压版安装和配置(带有搭建前端项目脚手架)
2018/12/06 NodeJs
puppeteer实现html截图的示例代码
2019/01/10 Javascript
vue项目中在外部js文件中直接调用vue实例的方法比如说this
2019/04/28 Javascript
vue.js实现备忘录demo
2019/06/26 Javascript
微信小程序实现带放大效果的轮播图
2020/05/26 Javascript
Python+MongoDB自增键值的简单实现
2016/11/04 Python
python实现发送邮件功能
2017/07/22 Python
python中如何正确使用正则表达式的详细模式(Verbose mode expression)
2017/11/08 Python
深入学习python多线程与GIL
2019/08/26 Python
Django Admin后台添加数据库视图过程解析
2020/04/01 Python
Python运算符+与+=的方法实例
2021/02/18 Python
Python使用paramiko连接远程服务器执行Shell命令的实现
2021/03/04 Python
详解CSS3的opacity属性设置透明效果的用法
2016/05/09 HTML / CSS
大一军训感言
2014/01/09 职场文书
降消项目实施方案
2014/03/30 职场文书
党的群众路线教育实践活动宣传标语口号
2014/06/06 职场文书
个人自荐书怎么写
2015/03/26 职场文书
Golang并发操作中常见的读写锁详析
2021/08/30 Golang