欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Angular通过指令动态添加组件问题

程序员文章站 2023-02-22 10:27:40
之前自己写的公共组件,都是会先引入,需要调起的时候再通过service控制公共组件状态、值、回调函数什么的。但是有一些场景不适合这种方式,还是动态添加组件更加好。通过写过的...

之前自己写的公共组件,都是会先引入,需要调起的时候再通过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等,看看源码,查查资料,总会梳理清楚的。

参考资料: