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

如何在Angular组件中按需加载不兼容SSR的NgApexchartsModule

解决Angular SSR中组件层面加载NgApexchartsModule的方案

完全可以在组件层面实现仅浏览器环境下加载NgApexchartsModule,以下是两种可行的落地方案:


方案1:封装动态加载组件

通过创建一个包装组件,在组件内部判断浏览器环境后,动态导入模块和图表组件,避免SSR阶段加载不兼容代码。

1.1 编写包装组件

import { Component, OnInit, ViewChild, ViewContainerRef, Inject, Injector } from '@angular/core';
import { PLATFORM_ID } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';

@Component({
  selector: 'app-apex-chart-wrapper',
  template: `<ng-template #chartHost></ng-template>`
})
export class ApexChartWrapperComponent implements OnInit {
  @ViewChild('chartHost', { read: ViewContainerRef }) chartHost!: ViewContainerRef;

  constructor(
    @Inject(PLATFORM_ID) private platformId: Object,
    private injector: Injector
  ) {}

  async ngOnInit() {
    if (isPlatformBrowser(this.platformId)) {
      // 动态导入NgApexcharts模块和你的图表业务组件
      const { NgApexchartsModule } = await import('ng-apexcharts');
      const { SalesChartComponent } = await import('./sales-chart/sales-chart.component');

      // 创建模块引用并生成组件实例
      const moduleRef = await NgApexchartsModule.create(this.injector);
      const componentFactory = moduleRef.componentFactoryResolver.resolveComponentFactory(SalesChartComponent);
      const componentRef = this.chartHost.createComponent(componentFactory);

      // 传递组件输入属性(按需添加)
      componentRef.instance.series = this.seriesData;
      componentRef.instance.chartConfig = this.chartOptions;
    }
  }

  // 定义需要传递给图表组件的数据
  seriesData = [{ name: '销售额', data: [31, 40, 28, 51, 42, 109, 100] }];
  chartOptions = {
    xaxis: { categories: ['1月', '2月', '3月', '4月', '5月', '6月', '7月'] }
  };
}

1.2 替换原组件引用

把页面中直接使用<apx-chart>的地方,替换为<app-apex-chart-wrapper>,服务器端渲染时只会渲染空模板,不会触发图表加载。

1.3 声明包装组件

将ApexChartWrapperComponent添加到根模块或共享模块的declarations数组中,无需在模块中导入NgApexchartsModule。


方案2:*ngIf结合浏览器环境判断(简化版)

如果不需要复杂的动态模块加载,可以直接在业务组件中通过isPlatformBrowser判断,仅在浏览器环境下渲染图表组件。

2.1 调整业务组件代码

import { Component, Inject } from '@angular/core';
import { PLATFORM_ID } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';

@Component({
  selector: 'app-dashboard',
  template: `
    <div class="dashboard-content">
      <!-- 仅浏览器环境渲染图表 -->
      <apx-chart 
        *ngIf="isBrowser"
        [series]="series" 
        [chart]="chartConfig" 
        [xaxis]="xaxis">
      </apx-chart>
    </div>
  `
})
export class DashboardComponent {
  isBrowser = isPlatformBrowser(this.platformId);

  // 图表配置
  series = [{ name: '访问量', data: [100, 200, 150, 300, 250] }];
  chartConfig = { type: 'bar' };
  xaxis = { categories: ['周一', '周二', '周三', '周四', '周五'] };

  constructor(@Inject(PLATFORM_ID) private platformId: Object) {}
}

2.2 模块层面的浏览器专属导入

在Angular CLI生成的SSR项目结构中,会有app.browser.module.ts文件,仅在浏览器环境加载,将NgApexchartsModule导入到这个文件中:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppModule } from './app.module';
import { AppComponent } from './app.component';
import { NgApexchartsModule } from 'ng-apexcharts';

@NgModule({
  imports: [
    BrowserModule.withServerTransition({ appId: 'serverApp' }),
    AppModule,
    NgApexchartsModule // 仅浏览器环境导入
  ],
  bootstrap: [AppComponent]
})
export class AppBrowserModule {}

关键注意事项

  • 动态加载时确保import()路径正确,避免编译阶段报错。
  • 如果需要传递组件输出事件,可通过componentRef.instance.eventName.subscribe()绑定。
  • 两种方案都能确保SSR阶段不会执行浏览器专属代码,彻底规避ng-apexcharts的兼容性问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 18:28:01