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文件 document.createElement
Oct 14 Javascript
javascript sudoku 数独智力游戏生成代码
Mar 27 Javascript
Javascript中封装window.open解决不兼容问题
Sep 28 Javascript
使用angularjs创建简单表格
Jan 21 Javascript
JS实现倒计时(天数、时、分、秒)
Nov 16 Javascript
使用cropper.js裁剪头像的实例代码
Sep 29 Javascript
JS的函数调用栈stack size的计算方法
Jun 24 Javascript
vuejs前后端数据交互之从后端请求数据的实例
Aug 11 Javascript
详解jQuery设置内容和属性
Apr 11 jQuery
Vue render函数实战之实现tabs选项卡组件
Apr 22 Javascript
JavaScript监听键盘事件代码实现
Jun 03 Javascript
vue使用better-scroll实现滑动以及左右联动
Jun 30 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 smarty模版引擎中的缓存应用
2009/12/11 PHP
ecshop 2.72如何修改后台访问地址
2015/03/03 PHP
Zend Framework框架Smarty扩展实现方法
2016/03/22 PHP
微信公众平台开发教程⑥ 微信开发集成类的使用图文详解
2019/04/10 PHP
加载 Javascript 最佳实践
2011/10/30 Javascript
JavaScript转换农历类实现及调用方法
2013/01/27 Javascript
Javascript之this关键字深入解析
2013/11/12 Javascript
jquery提交form表单时禁止重复提交的方法
2014/02/13 Javascript
jquery移动节点实例
2015/01/14 Javascript
Javascript数据结构与算法之列表详解
2015/03/12 Javascript
wangEditor编辑器失去焦点后仍然可以在原位置插入图片分析
2015/05/06 Javascript
JavaScript实现广告的关闭与显示效果实例
2015/07/02 Javascript
老生常谈JavaScript 正则表达式语法
2016/08/20 Javascript
js通过classname来获取元素的方法
2016/11/24 Javascript
vue实现全选、反选功能
2020/11/17 Javascript
微信小程序如何获取用户收货地址
2018/11/27 Javascript
新版小程序登录授权的方法
2018/12/12 Javascript
微信小程序实现卡片左右滑动效果的示例代码
2019/05/01 Javascript
bootstrap中的导航条实例代码详解
2019/05/20 Javascript
JavaScript 实现拖拽效果组件功能(兼容移动端)
2020/11/11 Javascript
python的numpy模块安装不成功简单解决方法总结
2017/12/23 Python
Python中的heapq模块源码详析
2019/01/08 Python
面向新手解析python Beautiful Soup基本用法
2020/07/11 Python
python中二分查找法的实现方法
2020/12/06 Python
英国安全产品购物网站:The Safe Shop
2017/03/20 全球购物
巴西服装和鞋子购物网站:Marisa
2018/10/25 全球购物
Nobody Denim官网:购买高级女士牛仔裤
2021/03/15 全球购物
空字符串(“”)和null的区别
2012/11/13 面试题
企业行政文员岗位职责
2013/12/03 职场文书
银行实习的自我鉴定
2013/12/10 职场文书
幼儿园中班新学期寄语
2014/01/18 职场文书
党的群众路线教育实践活动心得体会(医院)
2014/11/03 职场文书
2016庆祝教师节新闻稿
2015/11/25 职场文书
读《茶花女》有感:山茶花的盛开与凋零
2020/01/17 职场文书
浅谈Golang 切片(slice)扩容机制的原理
2021/06/09 Golang
Python利用capstone实现反汇编
2022/04/06 Python