Angular之动态加载组件

Angular组件的模板不会永远是固定的,在实际应用程序中,可能需要在运行期间动态加载组件。
参照Angular官方示例,练习一下Angular的动态加载组件。

1.确定组件加载位置

自定义一个指令,用于确定组件显示的锚点位置。

import { Directive, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[adHost]'
})
export class AdDirective {

  constructor(public viewContainerRef : ViewContainerRef) { }

}

2.定义组件

2.1标准化接口

定义一个标准化API接口组件,用于数据传递。

export interface AdComponent {
    data : any;
}

2.2实现类

定义它的实现类,用于在界面动态加载展示。
HeroJobAdComponent:

import { Component, OnInit, Input } from '@angular/core';
import { AdComponent } from './adcomponent';

@Component({
  template: `
    <div class="job-ad">
      <h4>{{data.headline}}</h4>
      {{data.body}}
    </div>
  `,
  styles: [
    '.job-ad {border: 1px solid gray; padding: 5px; padding-bottom: 20px; padding-left: 20px; border-radius: 10px; background-color: lightblue; color: black;}'
  ]
})
export class HeroJobAdComponent implements OnInit, AdComponent {
  @Input() data : any;

  constructor() { }

  ngOnInit(): void {
  }

}

HeroProfileComponent:

import { Component, OnInit, Input } from '@angular/core';
import { AdComponent } from './adcomponent';

@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>
  `,
  styles: [
    '.hero-profile {border: 1px solid gray; padding: 5px; padding-bottom: 20px; padding-left: 20px;border-radius: 10px;background-color: lightgreen;color: black;}'
  ]
})
export class HeroProfileComponent implements OnInit, AdComponent {

  @Input() data: any;

  constructor() { }

  ngOnInit(): void {
  }

}

2.3定义数据模型

创建一个数据模型类,用于定义数据结构。

import { Type } from '@angular/core';

export class AdItem {
    constructor(public component : Type<any>, public data : any) {}
}

2.4定义服务

创建一个服务,用于模拟获取数据。

import { Injectable } from '@angular/core';
import { AdItem } from './aditem';
import { HeroProfileComponent } from './heroprofile.component';
import { HeroJobAdComponent } from './herojobad.component';

@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' }
      )
    ];
  }
}

2.5定义主组件

创建主组件类,用于界面渲染。

import { Component, OnInit, OnDestroy, ComponentFactoryResolver, ViewChild, Input } from '@angular/core';
import { AdDirective } from './ad.directive';
import { AdItem } from './aditem';
import { AdComponent } from './adcomponent';

@Component({
  selector: 'app-ad-banner',
  template: `
    <div class="ad-banner-example">
      <h3>Advertisements</h3>
      <ng-template adHost></ng-template>
    </div>
  `,
  styles: [
    '.ad-banner-example {width: 400px;}',
  ]
})
export class AdBannerComponent implements OnInit, OnDestroy {
  @Input() ads : AdItem[] = [];
  currentAdIndex = -1;
  interval: any | undefined;

  @ViewChild(AdDirective, {static : true}) adHost !: AdDirective

  constructor(private componentFactoryResolver : ComponentFactoryResolver) { }
  
  ngOnInit(): void {
    this.loadComponent();
    this.getAds();
  }

  ngOnDestroy(): void {
    clearInterval(this.interval);
  }

  loadComponent() {
    this.currentAdIndex = (this.currentAdIndex + 1) % this.ads.length;
    const currentAdItem = this.ads[this.currentAdIndex];
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(currentAdItem.component);
    const viewContainerRef = this.adHost.viewContainerRef;
    viewContainerRef.clear();
    const componentRef = viewContainerRef.createComponent<AdComponent>(componentFactory);
    componentRef.instance.data = currentAdItem.data;
  }

  getAds() {
    this.interval = setInterval(() => {
      this.loadComponent();
    }, 3000);
  }
}

3.引入并加载组件

在父界面引入并加载组件:

import { NgModule } from '@angular/core';

import { PersonComponent } from '../person/person.component';
import { MenuComponent } from './menu/menu.component';
import { ContentComponent } from './content/content.component';
import { FormsModule } from '@angular/forms';
import { ChangehooktestComponent } from '../changehooktest/changehooktest.component';
import { BrowserModule } from '@angular/platform-browser';

import { AdBannerComponent } from '../dynamiccomponentstest/ad-banner.component';
import { HeroProfileComponent } from '../dynamiccomponentstest/heroprofile.component';
import { HeroJobAdComponent } from '../dynamiccomponentstest/herojobad.component';
import { AdService } from '../dynamiccomponentstest/ad.service';
import { AdDirective } from '../dynamiccomponentstest/ad.directive';

@NgModule({
  providers: [
    AdService
  ],
  declarations: [
    AdBannerComponent,
    HeroProfileComponent,
    HeroJobAdComponent,
    AdDirective,
  ],
  imports: [
    FormsModule,
    BrowserModule,
  ],
  exports: [
  ],
})
export class CommonModule { }

父组件:

import { Component, OnInit, ViewEncapsulation, ViewChild } from '@angular/core';
import { CommonService } from '../common.service';
import { AdItem } from '../../dynamiccomponentstest/aditem';
import { AdService } from '../../dynamiccomponentstest/ad.service';

@Component({
  selector: 'app-content',
  templateUrl: './content.component.html',
  styleUrls: ['./content.component.css'],
  encapsulation: ViewEncapsulation.None,
  providers: [CommonService],
})
export class ContentComponent implements OnInit {
  ads : AdItem[] = [];
  constructor(private adService : AdService) {}
  ngOnInit(): void {
    this.ads = this.adService.getAds();
  }
}

父组件模板:

<app-ad-banner [ads]="ads"></app-ad-banner>

最终显示效果是这样的:
在这里插入图片描述

4.附上程序源码

【点击下载】

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

^_^ 努力生活

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值