Angular 动态组件的使用(二)

Angular 动态组件的使用(一)

Angular 官网文档 - 动态组件

看了Angular官网动态组件的内容,相信很多朋友都是一脸懵逼进去,一脸懵逼出来,当然包括笔者。

官网以投放广告为例,每一则广告为一个独立组件,广告面板会动态切换不同的广告,即动态显示不同的组件,而不是同一个广告组件显示不同的广告内容。

1. 定义一个容器视图指令

组件是特殊的指令,组件可以作为动态组件的视图容器,指令同样可以。

定义一个广告容器的指令,该指令作为锚点来告诉 Angular 要把这些广告(即动态组件)插入到什么地方。

// ad.directive.ts
import { Directive, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[adContainer]',
})
export class AdDirective {
  // 注入了 ViewContainerRef 来获取对容器视图的访问权
  constructor(public viewContainerRef: ViewContainerRef) { }
}

2.定义广告基类组件

定义一个AdComponent组件作为广告基类,所有广告类型的组件将继承该基类组件,用于限制广告内容或其他功能。

// ad.component.ts
import { Component, OnInit } from '@angular/core';
export interface AdData {
	headline: string,   // 广告标题
	content: string,	// 广告内容
}

@Component({
  selector: 'ad',
  templateUrl: './ad.component.html',
  styleUrls: ['./ad.component.less']
})
export class AdComponent implements OnInit {
  data: AdData
  constructor() { }

  ngOnInit(): void {
  }
}

3.定义多种类型的广告组件

定义一个招聘广告组件

// job-ad.component.ts
import { Component, OnInit } from '@angular/core';
import { AdComponent, AdData } from '../ad/ad.component';

@Component({
  selector: 'job-ad',
  template: `
		<div>
		    <h3>工作招聘广告</h3>
		    <h4>{{data.headline}}</h4>
		    <h4>{{data.content}}</h4>
		</div>`,
  styleUrls: ['./job-ad.component.less']
})
export class JobAdComponent implements AdComponent, OnInit {
  data: AdData;
  constructor() { }
  
  ngOnInit(): void {
  }
}

定义一个其他类型的广告组件

// other-ad.component.ts
import { Component, OnInit } from '@angular/core';
import { AdComponent, AdData } from '../ad/ad.component';

@Component({
  selector: 'other-ad',
  template: `
		<div>
		    <h3>其他类型广告</h3>
		    <h4>{{data.headline}}</h4>
		    <h4>{{data.content}}</h4>
		</div>`,
  styleUrls: ['./job-ad.component.less']
})
export class OtherAdComponent implements AdComponent, OnInit {
  data: AdData;
  constructor() { }
  
  ngOnInit(): void {
  }
}

4.定义广告服务

定义一个广告服务,用于提供广告数据

// ad.service.ts
import { Injectable } from '@angular/core';
import { JobAdComponent } from '../components/job-ad/job-ad.component';
import { OtherAdComponent } from '../components/other-ad/other-ad.component';

@Injectable({
  providedIn: 'root'
})
export class AdService {
  adList = [ 
    {component: JobAdComponent, data: {headline: '招聘web前端开发', content: '待遇很好'}},
    {component: JobAdComponent, data: {headline: '招聘算法工程师', content: '六险一金'}},
    {component: OtherAdComponent, data: {headline: '金融广告', content: '理财保险'}},
    {component: OtherAdComponent, data: {headline: '汽车广告', content: '宝马奔驰'}},
  ]
  constructor() { }
}

5.定义广告面板组件

ng-template标签运用刚刚创建的容器视图adContainer,作为锚点来告诉 Angular 要把动态组件加载到这个位置。

<!-- ad-panel.component.html -->
<div>
    <h3>广告面板</h3>
    <hr/>
    <ng-template adContainer></ng-template>		<!-- 广告容器 -->
</div>
import { Component, OnInit, Input, ViewChild, ComponentFactoryResolver, ComponentFactory } from '@angular/core';
import { AdDirective } from '../../directives/ad.directive';
import { AdComponent } from '../ad/ad.component';

@Component({
  selector: 'ad-panel',
  templateUrl: './ad-panel.component.html',
  styleUrls: ['./ad-panel.component.less']
})
export class AdPanelComponent implements OnInit {
  @Input() ads: any[] = [];		// ads广告列表作为输入,数据来源于广告服务AdService
  currentAdIndex = -1;			// 记录广告列表的下标
  @ViewChild(AdDirective, {static: true}) adContainer!: AdDirective;
  interval: any;				// 定时器
  constructor(private componentFactoryResolver: ComponentFactoryResolver) { }

  ngOnInit(): void {
    this.loadComponent();
    this.getAds();
  }

  loadComponent() {
    this.currentAdIndex = this.ads.length ? (this.currentAdIndex + 1) % this.ads.length : 0; // 循环选取下标算法
    const adItem = this.ads[this.currentAdIndex];	// 当前的广告数据,包含广告组件模型和广告内容
    const componentFactory: ComponentFactory<AdComponent> = this.componentFactoryResolver.resolveComponentFactory(adItem.component);	// 调用resolveComponentFactory方法传入组件模板生成对应的组件工厂
    const viewContainerRef = this.adContainer.viewContainerRef;	 // 获取容器视图
    viewContainerRef.clear();	// 清空容器视图所有内容
    const componentRef = viewContainerRef.createComponent<AdComponent>(componentFactory); // 调用createComponent方法根据组件工厂创建对应的组件实例,并渲染在容器视图上
    componentRef.instance.data = adItem.data;	// 将广告内容的数据赋值给创建的组件实例
    
  }

  getAds() {
  	// 每3秒调用一次loadComponent方法来加载新的组件
    this.interval = setInterval(() => {
      this.loadComponent();
    }, 3000);
  }
}

效果图:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个Angular动态组件示例,该组件可以根据输入的组件类型动态创建并显示组件: app.component.ts ``` import { Component, ViewChild, ViewContainerRef, ComponentFactoryResolver } from '@angular/core'; import { DynamicComponent } from './dynamic.component'; @Component({ selector: 'app-root', template: ` <div #container></div> <button (click)="createComponent('dynamic')">Create Dynamic Component</button> `, }) export class AppComponent { @ViewChild('container', { read: ViewContainerRef }) container: ViewContainerRef; constructor(private resolver: ComponentFactoryResolver) {} createComponent(type: string) { // 根据组件类型获取组件工厂 const factory = this.resolver.resolveComponentFactory(DynamicComponent); // 创建组件实例 const componentRef = this.container.createComponent(factory); // 设置组件属性 componentRef.instance.type = type; } } ``` dynamic.component.ts ``` import { Component, Input } from '@angular/core'; @Component({ selector: 'app-dynamic', template: ` <div *ngIf="type"> Dynamic Component Type: {{ type }} </div> `, }) export class DynamicComponent { @Input() type: string; } ``` 在这个例子中,我们首先在`AppComponent`中使用`ViewChild`获取了一个`ViewContainerRef`引用,这个`ViewContainerRef`表示了一个可以动态添加组件的容器。然后,我们在`createComponent`方法中根据输入的组件类型获取了一个组件工厂,并使用`createComponent`方法创建了一个组件实例,并将其添加到了容器中。最后,我们还在`DynamicComponent`中添加了一个`Input`属性`type`,用于接收传递进来的组件类型。 使用这个动态组件的示例可以参考以下内容: ``` <app-root></app-root> ``` 在页面中添加了一个按钮,当点击按钮时,会调用`AppComponent`中的`createComponent`方法创建一个`DynamicComponent`实例,并将其添加到页面中的容器中。这个`DynamicComponent`实例会根据传递进来的组件类型显示不同的内容。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值