You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular如何编程式动态渲染传入组件实现可配置Widget仪表盘

Angular仪表盘动态组件渲染标准实现

1. 定义Widget接口类型

component属性直接使用Angular核心包提供的Type<any>类型,用来接收组件类本身:

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

export interface Widget {
  x: number;
  y: number;
  component: Type<any>;
}

2. 父组件传值

直接导入需要渲染的具体小部件组件类,赋值给component属性即可。注意所有动态渲染的组件,需要在所属模块的declarations中声明(Angular 13+基于Ivy引擎无需额外配置entryComponents,12及以下版本需要将动态组件加入模块的entryComponents数组;如果是Standalone独立组件,直接在使用处导入即可)。

// 导入自定义的小部件组件
import { StatCardWidgetComponent } from './widgets/stat-card-widget/stat-card-widget.component';
import { LineChartWidgetComponent } from './widgets/line-chart-widget/line-chart-widget.component';

widgets(): Widget[] {
  return [
    { x: 0, y: 0, component: StatCardWidgetComponent },
    { x: 1, y: 0, component: LineChartWidgetComponent },
  ];
}

3. dashboard-widget组件动态渲染实现

最简便的标准方案是使用Angular内置的*ngComponentOutlet指令,无需手动处理组件工厂逻辑,直接在模板中渲染传入的组件:
首先在dashboard-widget组件类中声明对应输入属性:

import { Component, Input, Type } from '@angular/core';

@Component({
  selector: 'dashboard-widget',
  templateUrl: './dashboard-widget.component.html'
})
export class DashboardWidgetComponent {
  @Input() x: number = 0;
  @Input() y: number = 0;
  @Input() component: Type<any>;
}

然后在模板中使用指令渲染动态组件:

<div class="widget-wrapper" [style.left.px]="x" [style.top.px]="y">
  <!-- 动态组件直接渲染在ng-container位置 -->
  <ng-container *ngComponentOutlet="component"></ng-container>
</div>

扩展:给动态组件传参

如果需要给动态组件传入@Input属性、绑定@Output事件,有两种常用方式:

  • Angular 14+版本可以直接给*ngComponentOutlet传inputs、outputs配置:
<ng-container
  *ngComponentOutlet="component; inputs: { title: '数据概览', data: widgetData }; outputs: { refresh: onRefresh }"
></ng-container>
  • 低版本或者需要更灵活控制的场景,可以用ViewContainerRef手动创建组件:
    首先在模板中标记组件挂载容器:
<div class="widget-wrapper" [style.left.px]="x" [style.top.px]="y">
  <ng-template #widgetHost></ng-template>
</div>

然后在组件类中获取容器引用,手动创建组件实例:

import { Component, Input, ViewChild, ViewContainerRef, Type, OnInit, OnDestroy } from '@angular/core';

export class DashboardWidgetComponent implements OnInit, OnDestroy {
  @Input() x: number = 0;
  @Input() y: number = 0;
  @Input() component: Type<any>;
  @Input() widgetData: any;

  @ViewChild('widgetHost', { read: ViewContainerRef, static: true }) widgetContainer: ViewContainerRef;
  private componentRef: any;

  ngOnInit() {
    this.widgetContainer.clear();
    this.componentRef = this.widgetContainer.createComponent(this.component);
    // 传入输入属性
    this.componentRef.instance.data = this.widgetData;
    // 订阅输出事件
    this.componentRef.instance.refresh.subscribe(() => {
      console.log('widget触发刷新');
    });
  }

  ngOnDestroy() {
    // 销毁组件实例避免内存泄漏
    this.componentRef?.destroy();
  }
}

内容的提问来源于stack exchange,提问作者Christoffer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 15:30:05