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

Angular集成Chartist首次加载报querySelectorAll为null 刷新后图表正常

错误原因

报错TypeError: Cannot read property 'querySelectorAll' of null是因为你在ngOnInit生命周期钩子中执行Chartist图表初始化,该阶段组件模板的DOM还未完成渲染挂载,通过类选择器.ct-chart-line无法匹配到对应元素,Chartist内部拿到空值后调用querySelectorAll触发报错。刷新后正常是因为浏览器缓存加快了DOM渲染速度,属于偶发正常,并非逻辑本身没问题。

解决方案

按照以下步骤修改即可:

  1. 调整生命周期钩子,将初始化逻辑移到DOM渲染完成后触发的ngAfterViewInit钩子中
  2. 使用@ViewChild获取组件内部DOM元素,替换全局类选择器,避免多实例冲突
  3. 兼容异步输入数据的场景,确保数据和DOM都准备完成后再初始化图表

具体代码修改

1. 修改 line.component.ts

// 新增导入AfterViewInit、ViewChild、ElementRef
import { Component, OnInit, Input, ViewEncapsulation, AfterViewInit, ViewChild, ElementRef } from '@angular/core';
import { ChartData } from '../chart.data.namespace';
import * as Chartist from 'chartist';
import { NChartist } from '../NChartist.namespace';
import {
  IBarChartOptions,
  IChartistAnimationOptions,
  IChartistData
} from 'chartist';

@Component({
  selector: 'app-line',
  templateUrl: './line.component.html',
  styleUrls: ['./line.component.css'],
  encapsulation:ViewEncapsulation.None,
})
// 实现AfterViewInit接口
export class LineComponent implements OnInit, AfterViewInit {
  chartline: any;
  // 用setter监听输入数据的变化,兼容异步传值
  @Input() set data(value: ChartData.LabelValue[]) {
    this._data = value;
    this.tryInitChart();
  }
  private _data: ChartData.LabelValue[];
  // 获取模板中的DOM元素
  @ViewChild('chartLineEl') chartLineEl: ElementRef;

  constructor() {
  }

  ngOnInit() {
    // 移除原有初始化逻辑
  }

  ngAfterViewInit() {
    // DOM渲染完成后尝试初始化图表
    this.tryInitChart();
  }

  // 统一判断初始化条件,避免重复代码
  private tryInitChart() {
    if (this.chartLineEl?.nativeElement && this._data?.length) {
      this.createLineChart();
    }
  }

  createLineChart() {
    let linedata: NChartist.Data = new NChartist.Data();

    this.prepareLineData(linedata);
    const prepared_l_data = {
      series: [linedata.series],
      labels: linedata.labels,
    }
    // 传入获取到的DOM元素,代替类选择器
    this.chartline = new Chartist.Line(this.chartLineEl.nativeElement, prepared_l_data,{})
    console.log(this.chartline);
    this.chartline.update();
    this.startAnimationForLineChart(this.chartline);
  }

  prepareLineData(linedata) {
    for (let i = 0; i < this._data.length; i++) {
      linedata.series[i] = this._data[i].value;
      linedata.labels[i] = this._data[i].label;
    }
  }

  startAnimationForLineChart(chart){
    let seq: any, delays: any, durations: any;
    seq = 0;
    delays = 80;
    durations = 500;

    chart.on('draw', function(data) {
      if(data.type === 'line' || data.type === 'area') {
        data.element.animate({
          d: {
            begin: 600,
            dur: 700,
            from: data.path.clone().scale(1, 0).translate(0, data.chartRect.height()).stringify(),
            to: data.path.clone().stringify(),
            easing: Chartist.Svg.Easing.easeOutQuint
          }
        });
      } else if(data.type === 'point') {
            seq++;
            data.element.animate({
              opacity: {
                begin: seq * delays,
                dur: durations,
                from: 0,
                to: 1,
                easing: 'ease'
              }
            });
        }
    });

    seq = 0;
  };
}

2. 修改 line.component.html

给图表容器增加模板引用变量#chartLineEl:

<body>
  <div class="card card-chart">
      <div class="card-header card-header-warning">
          <!-- 新增#chartLineEl -->
          <div class="ct-chart-line" id="chartline" #chartLineEl></div>
      </div>
      <div class="card-body">
          <h4 class="card-title">Line Chart</h4>
          <p class="card-category">
              <span class="text-success"><i class="fa fa-long-arrow-up"></i> 55% </span> increase in today
              sales.
          </p>
      </div>
      <div class="card-footer">
          <div class="stats">
              <i class="material-icons">access_time</i> updated 4 minutes ago
          </div>
      </div>
  </div>
</body>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 08:27:03