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 对象定义方法 简单易学
Mar 22 Javascript
自写的一个jQuery圆角插件
Oct 26 Javascript
防止jQuery ajax Load使用缓存的方法小结
Feb 22 Javascript
javascript中interval与setTimeOut的区别示例介绍
Mar 14 Javascript
浅谈javascript的call()、apply()、bind()的用法
Feb 21 Javascript
AngularJS 实现点击按钮获取验证码功能实例代码
Jul 13 Javascript
easyui datagrid 表格中操作栏 按钮图标不显示的解决方法
Jul 27 Javascript
laravel5.3 vue 实现收藏夹功能实例详解
Jan 21 Javascript
vue使用v-if v-show页面闪烁,div闪现的解决方法
Oct 12 Javascript
ElementUI radio组件选中小改造
Aug 12 Javascript
vue 遮罩层阻止默认滚动事件操作
Jul 28 Javascript
通过实例解析js可枚举属性与不可枚举属性
Dec 02 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使用strtotime获取上个月、下个月、本月的日期
2015/12/30 PHP
PHP+iframe图片上传实现即时刷新效果
2016/11/18 PHP
PHP中大括号'{}'用法实例总结
2017/02/08 PHP
jQuery 图像裁剪插件Jcrop的简单使用
2009/05/22 Javascript
用nodejs访问ActiveX对象,以操作Access数据库为例。
2011/12/15 NodeJs
Javascript获取窗口(容器)的大小及位置参数列举及简要说明
2012/12/09 Javascript
jQuery弹出层插件Lightbox_me使用指南
2015/04/21 Javascript
JavaScript基于ajax编辑信息用法实例
2015/07/15 Javascript
JS类的定义与使用方法深入探索
2016/11/26 Javascript
jQuery基于ajax操作json数据简单示例
2017/01/05 Javascript
VueJs路由跳转——vue-router的使用详解
2017/01/10 Javascript
使用jQuery操作DOM的方法小结
2017/02/27 Javascript
react开发中如何使用require.ensure加载es6风格的组件
2017/05/09 Javascript
Angularjs上传文件组件flowjs功能
2017/08/07 Javascript
详解使用jQuery.i18n.properties实现js国际化
2018/05/04 jQuery
JS利用prototype给类添加方法操作详解
2019/06/21 Javascript
JavaScript学习教程之cookie与webstorage
2019/06/23 Javascript
vue-cli脚手架的.babelrc文件用法说明
2020/09/11 Javascript
python和shell变量互相传递的几种方法
2013/11/20 Python
Python实现的最近最少使用算法
2015/07/10 Python
python看某个模块的版本方法
2018/10/16 Python
python 引用传递和值传递详解(实参,形参)
2020/06/05 Python
pycharm + django跨域无提示的解决方法
2020/12/06 Python
加拿大花店:1800Flowers.ca
2016/11/16 全球购物
台湾线上百货零售购物平台:friDay购物
2017/08/18 全球购物
波兰在线杂货店:Polski Koszyk
2019/11/02 全球购物
妇科医生自荐信
2013/11/05 职场文书
新闻学专业个人求职信写作
2014/02/04 职场文书
创业融资计划书
2014/04/25 职场文书
物流专业自荐信
2014/05/23 职场文书
党的群众路线教育实践活动制度建设计划
2014/11/03 职场文书
论文答辩开场白大全
2015/05/27 职场文书
校园歌手大赛主持词
2015/07/03 职场文书
企业安全生产检查制度
2015/08/06 职场文书
创业计划书之情侣餐厅
2019/09/29 职场文书
Python中super().__init__()测试以及理解
2021/12/06 Python