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 时间显示效果代码
Aug 23 Javascript
JQEasy-ui在IE9以下版本中二次加载的问题分析及处理方法
Jun 23 Javascript
jQuery原型属性和原型方法详解
Jul 07 Javascript
jQuery实现图片上传和裁剪插件Croppie
Nov 29 Javascript
JS常见问题之为什么点击弹出的i总是最后一个
Jan 05 Javascript
AngularJs 国际化(I18n/L10n)详解
Sep 01 Javascript
微信小程序 循环及嵌套循环的使用总结
Sep 26 Javascript
原生js实现form表单序列化的方法
Aug 02 Javascript
JS异步执行结果获取的3种解决方式
Feb 19 Javascript
layui 动态设置checbox 选中状态的例子
Sep 02 Javascript
VScode格式化ESlint方法(最全最好用方法)
Sep 10 Javascript
解决vue $http的get和post请求跨域问题
Jun 07 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
在PWS上安装PHP4.0正式版
2006/10/09 PHP
PHP迭代器的内部执行过程详解
2013/11/12 PHP
JavaScript中继承的一些示例方法与属性参考
2010/08/07 Javascript
javascript tips提示框组件实现代码
2010/11/19 Javascript
js给dropdownlist添加选项的小例子
2013/03/04 Javascript
JavaScript常用的弹出广告及背投广告实现方法
2015/02/06 Javascript
javascript模拟评分控件实现方法
2015/05/13 Javascript
异步JavaScript编程中的Promise使用方法
2015/07/28 Javascript
bootstrap+jQuery实现的动态进度条功能示例
2017/05/25 jQuery
vue 系列——vue2-webpack2框架搭建踩坑之路
2017/12/22 Javascript
图片懒加载imgLazyLoading.js使用详解
2020/09/15 Javascript
Vue 幸运大转盘实现思路详解
2019/05/06 Javascript
微信小程序使用npm包的方法步骤
2019/08/13 Javascript
Vue图片浏览组件v-viewer用法分析【支持旋转、缩放、翻转等操作】
2019/11/04 Javascript
JavaScript实现拖动对话框效果的实现代码
2020/10/12 Javascript
python实现简单ftp客户端的方法
2015/06/28 Python
详解Python的Django框架中Manager方法的使用
2015/07/21 Python
一款纯css3实现的鼠标悬停动画按钮
2014/12/29 HTML / CSS
基于Canvas+Vue的弹幕组件的实现
2019/07/23 HTML / CSS
HTML5拖放API实现拖放排序的实例代码
2017/05/11 HTML / CSS
澳大利亚婴儿、幼儿和儿童在线设计师商店:Smooch Baby
2019/02/16 全球购物
英国IT硬件供应商,定制游戏PC:Mesh Computers
2019/03/28 全球购物
比较基础的php面试题及答案-填空题
2014/04/26 面试题
班主任工作年限证明
2014/01/12 职场文书
联谊会主持词
2014/03/26 职场文书
项目投资建议书
2014/05/16 职场文书
公司周年庆典策划方案
2014/05/17 职场文书
中层干部培训方案
2014/06/16 职场文书
简易离婚协议书范本
2014/10/24 职场文书
先进工作者推荐材料
2014/12/23 职场文书
餐厅保洁员岗位职责
2015/04/10 职场文书
2015年重阳节主持词
2015/07/04 职场文书
2016计划生育先进个人事迹材料
2016/02/29 职场文书
中国式结婚:司仪主持词(范文)
2019/07/25 职场文书
centos8安装nginx1.9.1的详细过程
2021/08/02 Servers
HTML5中的DOCUMENT.VISIBILITYSTATE属性详解
2023/05/07 HTML / CSS