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判断图片尺寸和格式兼容IE
Sep 01 Javascript
使用jQuery实现返回顶部
Jan 26 Javascript
javascript基于DOM实现权限选择实例分析
May 14 Javascript
jQuery图片轮播滚动切换代码分享
Apr 20 Javascript
阻止表单提交按钮多次提交的完美解决方法
May 16 Javascript
JS实现六边形3D拖拽翻转效果的方法
Sep 11 Javascript
jQuery基于ajax实现页面加载后检查用户登录状态的方法
Feb 10 Javascript
详解Vue2.X的路由管理记录之 钩子函数(切割流水线)
May 02 Javascript
Angular.js中ng-include用法及多标签页面的实现方式详解
May 07 Javascript
javaScript和jQuery自动加载简单代码实现方法
Nov 24 jQuery
浅析java线程中断的办法
Jul 29 Javascript
js实现超级玛丽小游戏
Mar 18 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
全国FM电台频率大全 - 11 浙江省
2020/03/11 无线电
thinkphp获取栏目和文章当前位置的方法
2014/10/29 PHP
老生常谈PHP面向对象之标识映射
2017/06/21 PHP
在云虚拟主机部署thinkphp5项目的步骤详解
2017/12/21 PHP
360搜索引擎自动收录php改写方案
2018/04/28 PHP
微信公众平台开发教程⑥ 微信开发集成类的使用图文详解
2019/04/10 PHP
Laravel5.5 实现后台管理登录的方法(自定义用户表登录)
2019/09/30 PHP
javascript中onclick(this)用法介绍
2013/04/19 Javascript
nodejs redis 发布订阅机制封装实现方法及实例代码
2016/12/15 NodeJs
jQuery输入框密码的显示隐藏【代码分享】
2017/04/29 jQuery
javascript 作用于作用域链的详解
2017/09/27 Javascript
Angularjs中的$apply及优化使用详解
2018/07/02 Javascript
js实现敏感词过滤算法及实现逻辑
2018/07/24 Javascript
vue获取元素宽、高、距离左边距离,右,上距离等还有XY坐标轴的方法
2018/09/05 Javascript
antd组件Upload实现自己上传的实现示例
2018/12/18 Javascript
详解Vue、element-ui、axios实现省市区三级联动
2019/05/07 Javascript
深入剖析JavaScript instanceof 运算符
2019/06/14 Javascript
[48:44]2014 DOTA2国际邀请赛中国区预选赛5.21 TongFu VS HGT
2014/05/22 DOTA
python中requests爬去网页内容出现乱码问题解决方法介绍
2017/10/25 Python
浅谈python爬虫使用Selenium模拟浏览器行为
2018/02/23 Python
python 显示数组全部元素的方法
2018/04/19 Python
Django发送邮件功能实例详解
2019/09/02 Python
Tensorflow累加的实现案例
2020/02/05 Python
什么是python的函数体
2020/06/19 Python
HTML5 3D衣服摇摆动画特效
2016/03/17 HTML / CSS
北美三大旅游网站之一:Travelocity
2017/08/12 全球购物
复古斯堪的纳维亚儿童服装:Baby go Retro
2017/09/09 全球购物
香港现代设计家具品牌:Ziinlife Furniture
2018/11/13 全球购物
酷瑞网络科技面试题
2012/03/30 面试题
英文求职信结束语大全
2013/10/26 职场文书
党员干部2014全国两会学习心得体会
2014/03/10 职场文书
遗嘱继承公证书
2014/04/09 职场文书
观看信仰心得体会
2014/09/04 职场文书
地理信息科学专业推荐信
2014/09/08 职场文书
运动会宣传稿50字
2015/07/23 职场文书
2016年妇联“6﹒26国际禁毒日”宣传活动总结
2016/04/05 职场文书