Angular通过指令动态添加组件问题


Posted in Javascript onJuly 09, 2018

之前自己写的公共组件,都是会先引入,需要调起的时候再通过service控制公共组件状态、值、回调函数什么的。但是有一些场景不适合这种方式,还是动态添加组件更加好。通过写过的一个小组件来总结下。

创建组件

场景:鼠标移动到图标上时,展示解释性的说明文字。那就需要创建一个普通的tooltip组件。如下:

<aside class="hover-tip-wrapper">
 <span>{{tipText}}</span>
</aside>
import { Component, OnInit } from '@angular/core';
@Component({
 selector: 'app-hovertip',
 templateUrl: './hovertip.component.html',
 styleUrls: ['./hovertip.component.scss']
})
export class HovertipComponent implements OnInit {
 public tipText: string;
 constructor() { }
 ngOnInit() {
 }
}
.hover-tip-wrapper{
 width: max-content;
 position: absolute;
 height: 30px;
 line-height: 30px;
 bottom: calc(100% + 5px);
 right: calc( -10px - 100%);
 background-color: rgba(#000000,.8);
 padding: 0 5px;
 border-radius: 3px;
 &::after{
 content: '';
 position: absolute;
 height: 0;
 width: 0;
 border: 4px solid transparent;
 border-top-color: rgba(#000000,.8);
 left: 10px;
 top: 100%;
 }
 span {
 color: #ccc;
 font-size: 12px;
 }
}

非常简单的一个组件,tipText来接收需要展示的文字。

需要注意的是,声明组件的时候,除了需要添加到declarations中外,还记得要添加到entryComponents中。

entryComponents: [HovertipComponent],
declarations: [HovertipComponent, HovertipDirective]

那entryComponents这个配置项是做什么的呢?看源码注释,大概意思就是:Angular会为此配置项中的组件创建一个ComponentFactory,并存放在ComponentFactoryResolver中。动态添加组件时,需要用到组件工厂,所以此配置是必不可少的。

Angular通过指令动态添加组件问题

创建指令

通过指令为目标元素绑定事件,控制创建组件、传递tipText以及组件的销毁。

import { Input , Directive , ViewContainerRef , ComponentRef, ComponentFactory, HostListener , ComponentFactoryResolver} from '@angular/core';
import { HovertipComponent } from './hovertip.component';
@Directive({
 selector: '[appHovertip]'
})
export class HovertipDirective {
 public hovertip: ComponentRef<HovertipComponent>;
 public factory: ComponentFactory<HovertipComponent>;
 constructor(
 private viewContainer: ViewContainerRef,
 private resolver: ComponentFactoryResolver
 ) {
 // 获取对应的组件工厂
 this.factory = this.resolver.resolveComponentFactory(HovertipComponent);
 }
 @Input('appHovertip') tipText: string;
 
 // 绑定鼠标移入的事件
 @HostListener('mouseenter') onmouseenter() {
 // 清空所有的view 

 this.viewContainer.clear();
 // 创建组件
 this.hovertip = this.viewContainer.createComponent(this.factory);
 // 向组件实例传递参数
 this.hovertip.instance.tipText = this.tipText;
 }
 
 // 绑定鼠标移出时的事件
 @HostListener('mouseleave') onmouseleave() {
 if (this.hovertip) {

// 组件销毁
 this.hovertip.destroy();
 }
 }
}

通过ViewContainerRef类来管理视图,这里用到了创建组件。这个 专栏 解释的挺清楚的。这里用到了以下两个API,清除和创建。

Angular通过指令动态添加组件问题

createComponent方法接受ComponentFactoty类,创建后返回的ComponentRef类,可以获取到组件实例(instance),控制组件销毁。

Angular通过指令动态添加组件问题

大致思路是这样的,先获取到了HovertipComponent组件对于的componentFactory,监听鼠标移入事件,在触发事件时,通过ViewContainerRef类来创建组件,存下返回的组件componentRef(获取实例,销毁组件时需要用到),向组件实例传递tipText。监听鼠标移出事件,在事件触发时,销毁组件。

使用

在目标元素是绑定指令,同时传递tipText即可。

Angular通过指令动态添加组件问题

可以正常的创建和销毁。

Angular通过指令动态添加组件问题

总结

开始做的时候,主要是对这几个类比较懵,ViewContainerRef、ComponentRef、ComponentFactory、ComponentFactoryResolver等,看看源码,查查资料,总会梳理清楚的。

参考资料:

Javascript 相关文章推荐
JavaScript效率调优经验
Jun 04 Javascript
javascript处理table表格的代码
Dec 06 Javascript
TextArea设置MaxLength属性最大输入值的js代码
Dec 21 Javascript
原生Javascript封装的一个AJAX函数分享
Oct 11 Javascript
JS实现简洁、全兼容的拖动层实例
May 13 Javascript
js检测离开或刷新页面时表单数据是否更改的方法
Aug 02 Javascript
json与jsonp知识小结(推荐)
Aug 16 Javascript
Jquery组件easyUi实现表单验证示例
Aug 23 Javascript
vuejs项目打包之后的首屏加载优化及打包之后出现的问题
Apr 01 Javascript
Js 利用正则表达式和replace函数获取string中所有被匹配到的文本(推荐)
Oct 28 Javascript
JS获取本地地址及天气的方法实例小结
May 10 Javascript
处理canvas绘制图片模糊问题
May 11 Javascript
js实现左右两侧浮动广告
Jul 09 #Javascript
vue-router中scrollBehavior的巧妙用法
Jul 09 #Javascript
JavaScript解决浮点数计算不准确问题的方法分析
Jul 09 #Javascript
Vue自定义指令封装节流函数的方法示例
Jul 09 #Javascript
JavaScript实现创建自定义对象的常用方式总结
Jul 09 #Javascript
vue-cli配置环境变量的方法
Jul 09 #Javascript
JS逻辑运算符短路操作实例分析
Jul 09 #Javascript
You might like
PHP daddslashes 使用方法介绍
2012/10/26 PHP
关于js和php对url编码的处理方法
2014/03/04 PHP
php实例分享之html转为rtf格式
2014/06/02 PHP
php使用自定义函数实现汉字分割替换功能示例
2017/01/30 PHP
PHP函数rtrim()使用中的怪异现象分析
2017/02/24 PHP
PHP pthreads v3下worker和pool的使用方法示例
2020/02/21 PHP
如何利用PHP实现上传图片功能详解
2020/09/24 PHP
高性能WEB开发 flush让页面分块,逐步呈现 flush让页面分块,逐步呈现
2010/06/19 Javascript
google jQuery 引用文件,jQuery 引用地址集合(jquery 1.2.6至jquery1.5.2)
2011/04/24 Javascript
用js模拟struts2的多action调用示例
2014/05/19 Javascript
javascript常用函数归纳整理
2014/10/31 Javascript
JavaScript实现简单获取当前网页网址的方法
2015/11/09 Javascript
javascript之IE版本检测超简单方法
2016/08/20 Javascript
js 实现一些跨浏览器的事件方法详解及实例
2016/10/27 Javascript
详解微信小程序开发之下拉刷新 上拉加载
2016/11/24 Javascript
简单实现AngularJS轮播图效果
2020/04/10 Javascript
基于JSONP原理解析(推荐)
2017/12/04 Javascript
简单了解node npm cnpm的具体使用方法
2019/02/27 Javascript
通过图带你深入了解vue的响应式原理
2019/06/21 Javascript
微信小程序下拉框搜索功能的实现方法
2019/07/31 Javascript
详解Python的迭代器、生成器以及相关的itertools包
2015/04/02 Python
python3.5+tesseract+adb实现西瓜视频或头脑王者辅助答题
2018/01/17 Python
Python3中内置类型bytes和str用法及byte和string之间各种编码转换 问题
2018/09/27 Python
Python之修改图片像素值的方法
2019/07/03 Python
Flask配置Cors跨域的实现
2019/07/12 Python
python操作cfg配置文件方式
2019/12/22 Python
详解matplotlib中pyplot和面向对象两种绘图模式之间的关系
2021/01/22 Python
HTML5 本地存储之如果没有数据库究竟会怎样
2013/04/25 HTML / CSS
HTML5 Canvas+JS控制电脑或手机上的摄像头实例
2014/05/03 HTML / CSS
颇特女士:NET-A-PORTER(直邮中国)
2020/07/11 全球购物
文明社区申报材料
2014/08/21 职场文书
谢师宴答谢词
2015/01/05 职场文书
保研推荐信格式
2015/03/25 职场文书
简短清晨问候语
2015/11/10 职场文书
导游词之京东大峡谷旅游区
2019/10/29 职场文书
Spring JPA 增加字段执行异常问题及解决
2022/06/10 Java/Android