• Angular 动态组件


    Angular 动态组件

    实现步骤

    • Directive
    • HostComponent
    • 动态组件
    • AdService
    • 配置AppModule
    • 需要了解的概念

    Directive

    • 我们需要一个Directive来标记动态组件是在哪个容器组件内部进行渲染的。
    • 这个Directive可以获取对容器组件的引用。
    • 仅此而已。
    import { Directive, ViewContainerRef } from '@angular/core';
    
    @Directive({
      selector: '[appAd]',
    })
    export class AdDirective {
      constructor(public viewContainerRef: ViewContainerRef) { }
    }
    
    

    HostComponent

    • 我们需要一个容器组件,所有动态组件都是在这个容器组件中创建,销毁,重新创建。。。
    • 需要将动态组件需要展示的数据和动态组件进行绑定。
    import { Component, Input, AfterViewInit, ViewChild, ComponentFactoryResolver, OnDestroy } from '@angular/core';
    
    import { AdDirective } from './ad.directive';
    import { AdItem }      from './ad-item';
    import { AdComponent } from './ad.component';
    
    @Component({
      selector: 'app-add-banner',
      template: `
                  <div class="ad-banner">
                    <h3>Advertisements</h3>
                    <!-- hostElement 在此! -->
                    <ng-template appAd></ng-template>
                  </div>
                `
    })
    export class AdBannerComponent implements AfterViewInit, OnDestroy {
      @Input() ads: AdItem[];
      currentAddIndex: number = -1;
      @ViewChild(AdDirective) adHost: AdDirective;
      subscription: any;
      interval: any;
    
      constructor(private componentFactoryResolver: ComponentFactoryResolver) { }
    
      // 在 view 初始化结束后才开始创建动态组件
      ngAfterViewInit() {
        this.loadComponent();
        this.getAds();
      }
    
      ngOnDestroy() {
        clearInterval(this.interval);
      }
    
      loadComponent() {
        this.currentAddIndex = (this.currentAddIndex + 1) % this.ads.length;
        let adItem = this.ads[this.currentAddIndex];
    
        // 这里使用了工厂模式。其实Angular对于模板中出现的每一个Component都会创建一个ComponentFactory。在创建销毁时
        // 实际上使用的是组件工厂来创建组件的新实例。
        let componentFactory = this.componentFactoryResolver.resolveComponentFactory(adItem.component);
    
        let viewContainerRef = this.adHost.viewContainerRef;
        viewContainerRef.clear();
        // 传入对应的组件工厂来创建新的组件,并保存新组建的引用。
        let componentRef = viewContainerRef.createComponent(componentFactory);
        // 绑定数据
        (<AdComponent>componentRef.instance).data = adItem.data;
      }
    
      getAds() {
        this.interval = setInterval(() => {
          this.loadComponent();
        }, 3000);
      }
    }
    
    
    // add-item.ts
    import { Type } from '@angular/core';
    
    export class AdItem {
      constructor(public component: Type<any>, public data: any) {}
    }
    
    
    // ad.component.ts
    export interface AdComponent {
      data: any;
    }
    
    

    在AppComponent 中使用

    // app.component.ts
    
    import { Component, OnInit } from '@angular/core';
    
    import { AdService }         from './ad.service';
    import { AdItem }            from './ad-item';
    
    @Component({
      selector: 'app-root',
      template: `
        <div>
          <app-add-banner [ads]="ads"></app-add-banner>
        </div>
      `
    })
    export class AppComponent implements OnInit {
      ads: AdItem[];
    
      constructor(private adService: AdService) {}
    
      ngOnInit() {
        this.ads = this.adService.getAds();
      }
    }
    
    

    创建动态组件

    // hero-job-ad.component.ts
    import { Component, Input } from '@angular/core';
    
    import { AdComponent }      from './ad.component';
    
    @Component({
      template: `
        <div class="job-ad">
          <h4>{{data.headline}}</h4>
          {{data.body}}
        </div>
      `
    })
    export class HeroJobAdComponent implements AdComponent {
      @Input() data: any;
    
    }
    
    
    // hero-profile.component.ts
    import { Component, Input }  from '@angular/core';
    
    import { AdComponent }       from './ad.component';
    
    @Component({
      template: `
        <div class="hero-profile">
          <h3>Featured Hero Profile</h3>
          <h4>{{data.name}}</h4>
          <p>{{data.bio}}</p>
    
          <strong>Hire this hero today!</strong>
        </div>
      `
    })
    export class HeroProfileComponent implements AdComponent {
      @Input() data: any;
    }
    
    
    
    

    创建service

    import { Injectable }           from '@angular/core';
    
    import { HeroJobAdComponent }   from './hero-job-ad.component';
    import { HeroProfileComponent } from './hero-profile.component';
    import { AdItem }               from './ad-item';
    
    @Injectable()
    export class AdService {
      getAds() {
        return [
          new AdItem(HeroProfileComponent, {name: 'Bombasto', bio: 'Brave as they come'}),
    
          new AdItem(HeroProfileComponent, {name: 'Dr IQ', bio: 'Smart as they come'}),
    
          new AdItem(HeroJobAdComponent,   {headline: 'Hiring for several positions',
                                            body: 'Submit your resume today!'}),
    
          new AdItem(HeroJobAdComponent,   {headline: 'Openings in all departments',
                                            body: 'Apply today'}),
        ];
      }
    }
    
    

    配置 AppModule

    // app.module.ts
    import { BrowserModule }        from '@angular/platform-browser';
    import { NgModule }             from '@angular/core';
    import { AppComponent }         from './app.component';
    import { HeroJobAdComponent }   from './hero-job-ad.component';
    import { AdBannerComponent }    from './ad-banner.component';
    import { HeroProfileComponent } from './hero-profile.component';
    import { AdDirective }          from './ad.directive';
    import { AdService }            from './ad.service';
    
    @NgModule({
      imports: [ BrowserModule ],
      providers: [AdService],
      declarations: [ AppComponent,
                      AdBannerComponent,
                      HeroJobAdComponent,
                      HeroProfileComponent,
                      AdDirective ],
      // 注意这里,需要手动引入动态组件的class,放入 entryComponents数组中,这样
      // Angular才能为动态组件创建组件工厂。如果不写,Angular在模板中不会发现这两个组件的具体引用,
      // 可能在打包时将组件代码排除。
      entryComponents: [ HeroJobAdComponent, HeroProfileComponent ],
      bootstrap: [ AppComponent ]
    })
    export class AppModule {
      constructor() {}
    }
    
    
    
    ng serve
    

    完成。

    需要了解的概念

    • ViewContainerRef
    • ViewChild
    • ComponentFactoryResolver
    • ComponentFactory
    • ComponentRef
  • 相关阅读:
    QSettings读写注册表、配置文件
    QSettings介绍
    桥接模式
    Qt之启动外部程序
    StringJDBC更改数据库的两种方式
    写代码注意事项
    maven仓库
    java关闭流,解压缩后的清除
    Java删除文件夹和文件
    浏览器禁用后退
  • 原文地址:https://www.cnblogs.com/zhangfengyang/p/8432493.html
Copyright © 2020-2023  润新知