当前位置:Gxlcms > JavaScript > Angular通过指令动态添加组件问题

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

时间:2021-07-01 10:21:17 帮助过:2人阅读

之前自己写的公共组件,都是会先引入,需要调起的时候再通过service控制公共组件状态、值、回调函数什么的。但是有一些场景不适合这种方式,还是动态添加组件更加好。通过写过的一个小组件来总结下。

创建组件

  场景:鼠标移动到图标上时,展示解释性的说明文字。那就需要创建一个普通的tooltip组件。如下:

  1. <aside class="hover-tip-wrapper">
  2. <span>{{tipText}}</span>
  3. </aside>
  1. import { Component, OnInit } from '@angular/core';
  2. @Component({
  3. selector: 'app-hovertip',
  4. templateUrl: './hovertip.component.html',
  5. styleUrls: ['./hovertip.component.scss']
  6. })
  7. export class HovertipComponent implements OnInit {
  8. public tipText: string;
  9. constructor() { }
  10. ngOnInit() {
  11. }
  12. }
  1. .hover-tip-wrapper{
  2. width: max-content;
  3. position: absolute;
  4. height: 30px;
  5. line-height: 30px;
  6. bottom: calc(100% + 5px);
  7. right: calc( -10px - 100%);
  8. background-color: rgba(#000000,.8);
  9. padding: 0 5px;
  10. border-radius: 3px;
  11. &::after{
  12. content: '';
  13. position: absolute;
  14. height: 0;
  15. width: 0;
  16. border: 4px solid transparent;
  17. border-top-color: rgba(#000000,.8);
  18. left: 10px;
  19. top: 100%;
  20. }
  21. span {
  22. color: #ccc;
  23. font-size: 12px;
  24. }
  25. }

  非常简单的一个组件,tipText来接收需要展示的文字。

  需要注意的是,声明组件的时候,除了需要添加到declarations中外,还记得要添加到entryComponents中。

  1. entryComponents: [HovertipComponent],
  2. declarations: [HovertipComponent, HovertipDirective]

  那entryComponents这个配置项是做什么的呢?看源码注释,大概意思就是:Angular会为此配置项中的组件创建一个ComponentFactory,并存放在ComponentFactoryResolver中。动态添加组件时,需要用到组件工厂,所以此配置是必不可少的。

创建指令

  通过指令为目标元素绑定事件,控制创建组件、传递tipText以及组件的销毁。

  1. import { Input , Directive , ViewContainerRef , ComponentRef, ComponentFactory, HostListener , ComponentFactoryResolver} from '@angular/core';
  2. import { HovertipComponent } from './hovertip.component';
  3. @Directive({
  4. selector: '[appHovertip]'
  5. })
  6. export class HovertipDirective {
  7. public hovertip: ComponentRef<HovertipComponent>;
  8. public factory: ComponentFactory<HovertipComponent>;
  9. constructor(
  10. private viewContainer: ViewContainerRef,
  11. private resolver: ComponentFactoryResolver
  12. ) {
  13. // 获取对应的组件工厂
  14. this.factory = this.resolver.resolveComponentFactory(HovertipComponent);
  15. }
  16. @Input('appHovertip') tipText: string;
  17.  
  18. // 绑定鼠标移入的事件
  19. @HostListener('mouseenter') onmouseenter() {
  20.    // 清空所有的view
  21.    this.viewContainer.clear();
  22. // 创建组件
  23. this.hovertip = this.viewContainer.createComponent(this.factory);
  24. // 向组件实例传递参数
  25. this.hovertip.instance.tipText = this.tipText;
  26. }
  27.  
  28.  // 绑定鼠标移出时的事件
  29. @HostListener('mouseleave') onmouseleave() {
  30. if (this.hovertip) {
  31.   // 组件销毁
  32. this.hovertip.destroy();
  33. }
  34. }
  35. }

  通过ViewContainerRef类来管理视图,这里用到了创建组件。这个 专栏 解释的挺清楚的。这里用到了以下两个API,清除和创建。

  createComponent方法接受ComponentFactoty类,创建后返回的ComponentRef类,可以获取到组件实例(instance),控制组件销毁。

  大致思路是这样的,先获取到了HovertipComponent组件对于的componentFactory,监听鼠标移入事件,在触发事件时,通过ViewContainerRef类来创建组件,存下返回的组件componentRef(获取实例,销毁组件时需要用到),向组件实例传递tipText。监听鼠标移出事件,在事件触发时,销毁组件。

使用

  在目标元素是绑定指令,同时传递tipText即可。

  可以正常的创建和销毁。

总结

  开始做的时候,主要是对这几个类比较懵,ViewContainerRef、ComponentRef、ComponentFactory、ComponentFactoryResolver等,看看源码,查查资料,总会梳理清楚的。

参考资料:

https://www.gxlcms.com/article/114683.htm

https://www.gxlcms.com/article/112123.htm

人气教程排行