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 相关文章推荐
JS原型对象通俗&quot;唱法&quot;
Dec 27 Javascript
javascript删除option选项的多种方法总结
Nov 22 Javascript
jQuery学习笔记之 Ajax操作篇(一) - 数据加载
Jun 23 Javascript
基于jquery实现等比缩放图片
Dec 03 Javascript
node.js中的fs.utimes方法使用说明
Dec 15 Javascript
解决ueditor jquery javascript 取值问题
Dec 30 Javascript
javascript实现textarea中tab键的缩排处理方法
Jun 26 Javascript
解析预加载显示图片艺术
Dec 05 Javascript
Jquery Easyui验证组件ValidateBox使用详解(20)
Dec 18 Javascript
详解Angular4 路由设置相关
Aug 26 Javascript
Vue.js用法详解
Nov 13 Javascript
基于VSCode调试网页JavaScript代码过程详解
Jul 20 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
一个程序下载的管理程序(三)
2006/10/09 PHP
用PHP查询域名状态whois的类
2006/11/25 PHP
深入理解用mysql_fetch_row()以数组的形式返回查询结果
2013/06/05 PHP
php中session过期时间设置及session回收机制介绍
2014/05/05 PHP
javascript 面向对象 function类
2010/05/13 Javascript
jquery获取iframe中的dom对象(两种方法)
2013/07/02 Javascript
ExtJs设置GridPanel表格文本垂直居中示例
2013/07/15 Javascript
禁止页面刷新让F5快捷键及右键都无效
2014/01/22 Javascript
利用函数的惰性载入提高javascript代码执行效率
2014/05/05 Javascript
jquery的ajax跨域请求原理和示例
2014/05/08 Javascript
jQuery css() 方法动态修改CSS属性
2016/09/25 Javascript
angular2+node.js express打包部署的实战
2017/07/27 Javascript
通过jquery获取上传文件名称、类型和大小的实现代码
2018/04/19 jQuery
详解Angular6 热加载配置方案
2018/08/18 Javascript
对Vue beforeRouteEnter 的next执行时机详解
2018/08/25 Javascript
javascript实现文本框标签验证的实例代码
2018/10/14 Javascript
在webstorm开发微信小程序之使用阿里自定义字体图标的方法
2018/11/15 Javascript
vue 双向数据绑定的实现学习之监听器的实现方法
2018/11/30 Javascript
微信小程序拍照和摄像功能实现方法示例
2019/02/01 Javascript
vue-cli脚手架打包静态资源请求出错的原因与解决
2019/06/06 Javascript
使用layer.msg 时间设置不起作用的解决方法
2019/09/12 Javascript
[03:23]我的刀塔你不可能这么可爱 第一期金萌萌的故事
2014/06/20 DOTA
Python中json格式数据的编码与解码方法详解
2016/07/01 Python
对python append 与浅拷贝的实例讲解
2018/05/04 Python
Django框架的中的setting.py文件说明详解
2018/10/15 Python
python 图像处理画一个正弦函数代码实例
2019/09/10 Python
完美解决Pycharm中matplotlib画图中文乱码问题
2021/01/11 Python
日本运动品牌美津浓官方购物网站:MIZUNO SHOP
2016/08/21 全球购物
运动鞋、足球鞋和慕尼黑球衣:Sport Münzinger
2019/08/26 全球购物
JMS中Topic和Queue有什么区别
2013/05/15 面试题
公司离职证明范本
2014/01/13 职场文书
企业爱岗敬业演讲稿
2014/09/04 职场文书
12.4全国法制宣传日活动总结
2014/11/01 职场文书
音乐之声观后感
2015/06/04 职场文书
公司保洁员管理制度
2015/08/04 职场文书
Vue组件化(ref,props, mixin,.插件)详解
2022/05/15 Vue.js