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 相关文章推荐
jquery下组织javascript代码(js函数化)
Aug 25 Javascript
jquery dialog open后,服务器端控件失效的快速解决方法
Dec 19 Javascript
JSuggest自动匹配下拉框使用方法(示例代码)
Dec 27 Javascript
javascript作用域和闭包使用详解
Apr 25 Javascript
Javascript 读取操作Sql中的Xml字段
Oct 09 Javascript
JS button按钮实现submit按钮提交效果
Nov 01 Javascript
Angularjs中ng-repeat的简单实例
Aug 25 Javascript
微信小程序调用摄像头隐藏式拍照功能
Aug 22 Javascript
对Vue- 动态元素属性及v-bind和v-model的区别详解
Aug 27 Javascript
解决layui laydate 时间控件一闪而过的问题
Sep 28 Javascript
Node.js API详解之 string_decoder用法实例分析
Apr 29 Javascript
JSON 入门教程基础篇 json入门学习笔记
Sep 22 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动态变静态原理
2006/11/25 PHP
PHP中的按位与和按位或操作示例
2014/01/27 PHP
php简单读取.vcf格式文件的方法示例
2017/09/02 PHP
php的无刷新操作实现方法分析
2020/02/28 PHP
js修改table中Td的值(定义td的单击事件)
2013/01/10 Javascript
node.js中的http.request方法使用说明
2014/12/14 Javascript
node.js中的fs.readdirSync方法使用说明
2014/12/17 Javascript
JS控制网页动态生成任意行列数表格的方法
2015/03/09 Javascript
bootstrap模态框跳转到当前模板页面 框消失了而背景存在问题的解决方法
2020/11/30 Javascript
Bootstrap的基本应用要点浅析
2016/12/19 Javascript
AngularJS实现网站换肤实例
2021/02/19 Javascript
js模拟微博发布消息
2017/02/23 Javascript
微信小程序带动画弹窗组件使用方法详解
2018/11/27 Javascript
Vue实现远程获取路由与页面刷新导致404错误的解决
2019/01/31 Javascript
[06:07]DOTA2-DPC中国联赛3月5日Recap集锦
2021/03/11 DOTA
python使用cookielib库示例分享
2014/03/03 Python
将Django使用的数据库从MySQL迁移到PostgreSQL的教程
2015/04/11 Python
在Python的Flask框架中实现全文搜索功能
2015/04/20 Python
Python 文件管理实例详解
2015/11/10 Python
python实现AES加密和解密
2019/03/27 Python
Python 实现向word(docx)中输出
2020/02/13 Python
python实现微信打飞机游戏
2020/03/24 Python
python 等差数列末项计算方式
2020/05/03 Python
Scrapy爬虫文件批量运行的实现
2020/09/30 Python
python 实现弹球游戏的示例代码
2020/11/17 Python
pycharm 多行批量缩进和反向缩进快捷键介绍
2021/01/15 Python
python 指定源路径来解决import问题的操作
2021/03/04 Python
HTML5+CSS3模仿优酷视频截图功能示例
2017/01/05 HTML / CSS
网络维护管理员的自我评价分享
2013/11/11 职场文书
高中体育教学反思
2014/01/29 职场文书
党的群众路线个人对照检查材料
2014/09/23 职场文书
2014最新版群众路线四风整改措施
2014/09/24 职场文书
2014酒店客房部工作总结
2014/12/16 职场文书
运动会开幕词
2015/01/28 职场文书
使用这 6个Vue加载动画库来减少我们网站的跳出率
2021/05/18 Vue.js
MySQL中rank() over、dense_rank() over、row_number() over用法介绍
2022/03/23 MySQL