Angular使用*ngIf控制Chart.js容器时报无法获取上下文错误如何解决
报错原因
*ngIf指令的逻辑是当绑定条件为false时,会直接将对应元素从DOM树中移除,不会进行渲染。你在ngOnInit生命周期中初始化Chart实例时,默认showAna为false,id为chart的canvas元素还没有被渲染到页面中,Chart.js无法获取到对应的画布上下文,因此抛出该错误。
当你移除*ngIf时,canvas元素在页面初始化时就会渲染,因此初始化Chart时可以正常找到对应元素,不会报错。
解决方案
你可以选择以下任意一种方式修复问题:
方案1:调整图表初始化时机(推荐)
将图表初始化逻辑从ngOnInit中抽离,仅在切换到图表标签时执行初始化,同时避免重复初始化图表实例:
修改后的TS代码:
// 新增变量标记图表是否已初始化 chartInited = false; async ngOnInit(): Promise<void> { // 这里保留你原来获取表格和图表数据的逻辑 // 不要在这里初始化Chart this.loading = false; } // 抽离图表初始化方法 initChart() { if (this.chartInited) return; // 避免重复初始化 this.chart = new Chart('chart', { type: 'line', data: { labels: this.mesi, datasets: [{ label: 'totale va ufficiali', data: this.totEffortva, backgroundColor: [ 'rgba(255, 99, 132, 0.2)'], borderColor: [ 'rgba(255, 99, 132, 1)'], borderCapStyle: 'butt', borderDash: [], borderDashOffset: 0.0, borderJoinStyle: 'miter', pointBorderColor: "white", pointBackgroundColor: "black", pointBorderWidth: 1, pointHoverRadius: 8, pointHoverBackgroundColor: "brown", pointHoverBorderColor: "yellow", pointHoverBorderWidth: 2, pointRadius: 4, pointHitRadius: 10, },{ label: "totale giornate impegnate", fill: true, lineTension: 0.1, backgroundColor: "rgba(167,105,0,0.4)", borderColor: "rgb(167, 105, 0)", borderCapStyle: 'butt', borderDash: [], borderDashOffset: 0.0, borderJoinStyle: 'miter', pointBorderColor: "white", pointBackgroundColor: "black", pointBorderWidth: 1, pointHoverRadius: 8, pointHoverBackgroundColor: "brown", pointHoverBorderColor: "yellow", pointHoverBorderWidth: 2, pointRadius: 4, pointHitRadius: 10, data: this.totprog, spanGaps: false, }] }, options: { responsive: true, plugins: { legend: { position: 'top', }, title: { display: true, text: 'Chart.js Line Chart' } } }, }); this.chartInited = true; } ana(show:boolean){ this.showAna = show; // 切换到图表标签时初始化图表 if(show && !this.loading) { this.initChart(); } }
修改后的HTML代码:
删除canvas标签内的{{chart}},该写法无实际作用还可能干扰画布渲染:
<div> <button class="tablink" style="float: left;" (click)="ana(false)">DATI TABELLARI</button> <button class="tablink" style="float: right;" (click)="ana(true)">GRAFICO</button> </div> <div *ngIf="showAna!=true && loading==false"> TABLES </div> <div *ngIf="showAna==true && loading==false"> CHART <div id="divCh"> <canvas id="chart"></canvas> </div> </div>
方案2:使用[hidden]代替*ngIf(改造成本最低)
[hidden]指令仅会控制元素的显示隐藏,不会将元素从DOM中移除,因此页面初始化时canvas元素存在,可正常初始化Chart:
<div> <button class="tablink" style="float: left;" (click)="ana(false)">DATI TABELLARI</button> <button class="tablink" style="float: right;" (click)="ana(true)">GRAFICO</button> </div> <!-- 条件和*ngIf相反,hidden为true时隐藏元素 --> <div [hidden]="showAna==true || loading==true"> TABLES </div> <div [hidden]="showAna!=true || loading==true"> CHART <div id="divCh"> <canvas id="chart"></canvas> </div> </div>
TS代码无需调整,仅需要删除canvas内的{{chart}}即可。
内容的提问来源于stack exchange,提问作者pietro
相关产品推荐
相关产品推荐

