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中的apply()方法和call()方法使用介绍
Jul 25 Javascript
js相册效果代码(点击创建即可)
Apr 16 Javascript
根据选择不同的下拉值出现相对应的文本输入框
Aug 01 Javascript
用jQuery toggleClass 实现鼠标移上变色
May 14 Javascript
在AngularJS中如何使用谷歌地图把当前位置显示出来
Jan 25 Javascript
JavaScript制作简单的日历效果
Mar 10 Javascript
jQuery实现获取动态添加的标签对象示例
Jun 28 jQuery
layui table设置前台过滤转义等方法
Aug 17 Javascript
JavaScript 面向对象基础简单示例
Oct 02 Javascript
Nuxt v-bind绑定img src不显示的解决
Dec 05 Javascript
jquery实现直播视频弹幕效果
Feb 25 jQuery
部署vue+Springboot前后端分离项目的步骤实现
May 31 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+mysql数据库实现无限分类的方法
2014/12/12 PHP
PHP防盗链的基本思想 防盗链的设置方法
2015/09/25 PHP
细品javascript 寻址,闭包,对象模型和相关问题
2009/04/27 Javascript
jQuery EasyUI API 中文文档 - NumberSpinner数值微调器使用介绍
2011/10/21 Javascript
jQuery UI Autocomplete 1.8.16 中文输入修正代码
2012/04/16 Javascript
jquery对dom的操作常用方法整理
2013/06/25 Javascript
jQuery函数map()和each()介绍及异同点分析
2014/11/08 Javascript
JS制作简单的三级联动
2015/03/18 Javascript
jQuery实现简易的天天爱消除小游戏
2015/10/16 Javascript
详解JavaScript的变量和数据类型
2015/11/27 Javascript
js链表操作(实例讲解)
2017/08/29 Javascript
深入浅析Vue全局组件与局部组件的区别
2018/06/15 Javascript
vue实现日历备忘录功能
2020/09/24 Javascript
微信小程序实现吸顶效果
2020/01/08 Javascript
JS实现烟花爆炸效果
2020/03/10 Javascript
JS实现进度条动态加载特效
2020/03/25 Javascript
微信小程序实现多张图片上传功能
2020/11/18 Javascript
JavaScript实现京东快递单号查询
2020/11/30 Javascript
python3实现短网址和数字相互转换的方法
2015/04/28 Python
一个基于flask的web应用诞生 flask和mysql相连(4)
2017/04/11 Python
python网络爬虫学习笔记(1)
2018/04/09 Python
python破解zip加密文件的方法
2018/05/31 Python
python将txt文档每行内容循环插入数据库的方法
2018/12/28 Python
python接口自动化(十六)--参数关联接口后传(详解)
2019/04/16 Python
实现ECharts双Y轴左右刻度线一致的例子
2020/05/16 Python
Django Model中字段(field)的各种选项说明
2020/05/19 Python
Nike瑞典官方网站:Nike.com (SE)
2018/11/26 全球购物
县优秀教师事迹材料
2014/01/31 职场文书
在教室放鞭炮的检讨书
2014/09/28 职场文书
2014年汽车销售工作总结
2014/12/01 职场文书
2015员工年度考核评语
2015/03/25 职场文书
《分数乘法》教学反思
2016/02/24 职场文书
导游词之鲁迅祖居
2019/10/17 职场文书
MySQL 查询速度慢的原因
2021/05/25 MySQL
再谈python_tkinter弹出对话框创建
2022/03/20 Python
springboot实现string转json json里面带数组
2022/06/16 Java/Android