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 Event学习补遗 addEventSimple
Feb 11 Javascript
使用jQuery模板来展现json数据的代码
Oct 22 Javascript
图片img的src不变让浏览器重新加载实现方法
Mar 29 Javascript
Jquery遍历checkbox获取选中项value值的方法
Feb 13 Javascript
JS不能跨域借助jquery获取IP地址的方法
Aug 20 Javascript
JS实现点击文字对应DIV层不停闪动效果的方法
Mar 02 Javascript
JavaScript实现字符串与日期的互相转换及日期的格式化
Mar 07 Javascript
Javascript动画效果(3)
Oct 11 Javascript
微信小程序带动画弹窗组件使用方法详解
Nov 27 Javascript
spring+angular实现导出excel的实现代码
Feb 27 Javascript
基于Vue+ElementUI的省市区地址选择通用组件
Nov 20 Javascript
vue组件冲突之引用另一个组件出现组件不显示的问题
Apr 13 Vue.js
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
yii实现图片上传及缩略图生成的方法
2014/12/04 PHP
php实现可运算的验证码
2015/11/10 PHP
[原创]PHP简单开启curl的方法(测试可行)
2016/01/11 PHP
PHP性能分析工具xhprof的安装使用与注意事项
2017/12/19 PHP
php正则表达式使用方法整理集合
2020/01/31 PHP
gearman管理工具GearmanManager的安装与php使用方法示例
2020/02/27 PHP
jquery解析JSON数据示例代码
2014/03/17 Javascript
js动态添加onclick事件可传参数与不传参数
2014/07/29 Javascript
下拉框select的绑定示例
2014/09/04 Javascript
Javascript获取当前日期的农历日期代码
2014/10/08 Javascript
jQuery定义背景动态切换效果的方法
2015/03/23 Javascript
[原创]JQuery 在表单提交之前修改 提交的值
2016/04/14 Javascript
jQuery实现iframe父窗体和子窗体的相互调用
2016/06/17 Javascript
微信小程序实现瀑布流布局与无限加载的方法详解
2017/05/12 Javascript
微信小程序云函数使用mysql数据库过程详解
2019/08/07 Javascript
利用JavaScript的Map提升性能的方法详解
2019/08/14 Javascript
jQuery实现简易聊天框
2020/02/08 jQuery
vue el-tree 默认展开第一个节点的实现代码
2020/05/15 Javascript
用Python制作简单的朴素基数估计器的教程
2015/04/01 Python
Python性能提升之延迟初始化
2016/12/04 Python
python队列通信:rabbitMQ的使用(实例讲解)
2017/12/22 Python
Python基于mysql实现学生管理系统
2019/02/21 Python
Python的高阶函数用法实例分析
2019/04/11 Python
python图片二值化提高识别率代码实例
2019/08/24 Python
python GUI库图形界面开发之PyQt5信号与槽的高级使用技巧(自定义信号与槽)详解与实例
2020/03/06 Python
python和C++共享内存传输图像的示例
2020/10/27 Python
HTML5的新特性(1)
2016/03/03 HTML / CSS
七匹狼男装广告词
2014/03/21 职场文书
应届大专毕业生自我鉴定
2014/04/08 职场文书
船舶工程技术专业求职信
2014/08/07 职场文书
组工干部演讲稿
2014/09/02 职场文书
实践论读书笔记
2015/06/29 职场文书
学习焦裕禄先进事迹心得体会
2016/01/23 职场文书
html中显示特殊符号(附带特殊字符对应表)
2021/06/21 HTML / CSS
html5调用摄像头实例代码
2021/06/28 HTML / CSS
MySQL数据库配置信息查看与修改方法详解
2022/06/25 MySQL