Chart.js结合Ajax传数组时柱状图无法显示数据的解决方法
问题现象
使用Chart.js开发柱状图时,手动填写labels与data字段的静态值图表可正常运行,但传入Ajax动态拉取的数组变量时,图表始终为空白状态,无法正常展示数据。
问题根因
核心问题有两个:
- 异步请求时序错误:Ajax默认是异步执行逻辑,发起3个接口请求后,代码不会等待接口返回、数组填充完成就直接初始化Chart实例。此时
categoryName、usedBudgetTmonth、usedBudgetLmonth三个数组均为空数组,Chart拿到空数据自然渲染空白。后续接口返回数据后往数组push内容时,Chart不会自动监听数组变化触发重渲染。 - 数据匹配逻辑错误:原有嵌套循环的逻辑会在遍历预算数据时,无论是否匹配当前分类都执行push操作,最终生成的数据数组长度和labels长度不匹配,即使时序正确也会出现数据错位、渲染异常的问题。
修复方案
等所有接口数据全部返回后,统一做数据对齐处理,再初始化图表即可,修正后的完整代码如下:
const ctxOne = document.querySelector('#myChartOne'); // 封装接口请求为Promise const getCategoryList = () => { return new Promise(resolve => { $.ajax({ url: "../controllers/getCategoryNames.php", method: "GET", success: data => resolve(JSON.parse(data)) }) }) } const getThisMonthBudget = () => { return new Promise(resolve => { $.ajax({ url: "../controllers/budgetUsedTmonth.php", method: "GET", success: data => resolve(JSON.parse(data)) }) }) } const getLastMonthBudget = () => { return new Promise(resolve => { $.ajax({ url: "../controllers/budgetUsedLmonth.php", method: "GET", success: data => resolve(JSON.parse(data)) }) }) } // 等待所有接口返回后再处理数据、初始化图表 Promise.all([getCategoryList(), getThisMonthBudget(), getLastMonthBudget()]).then(results => { const [categoryData, thisMonthData, lastMonthData] = results; // 提取分类标签 const labels = categoryData.map(item => item.category_name); // 按分类对齐生成本月预算占比数据 const thisMonthPct = labels.map(cateName => { const matchItem = thisMonthData.find(item => item.category_name === cateName); return matchItem ? matchItem.pct : 0; }); // 按分类对齐生成上月预算占比数据 const lastMonthPct = labels.map(cateName => { const matchItem = lastMonthData.find(item => item.category_name === cateName); return matchItem ? matchItem.pct : 0; }); // 初始化图表 new Chart(ctxOne, { type: 'bar', data: { labels: labels, datasets: [ { label: 'This Month', data: thisMonthPct, backgroundColor: 'rgba(255, 99, 132, 0.2)', borderColor: 'rgba(255, 99, 132, 1)', borderWidth: 1 }, { label: 'Last Month', data: lastMonthPct, backgroundColor: 'rgba(54, 162, 235, 0.2)', borderColor: 'rgba(54, 162, 235, 1)', borderWidth: 1 } ] } }); })
补充说明
如果业务场景需要先初始化空图表,后续再动态填充数据,不要直接给原数组push内容,需要拿到新数据后替换图表实例的data属性,再调用update()方法手动触发重渲染:
// 假设已经提前初始化了myChartOne实例 myChartOne.data.labels = newLabels; myChartOne.data.datasets[0].data = newThisMonthData; myChartOne.data.datasets[1].data = newLastMonthData; // 触发重渲染 myChartOne.update();
内容的提问来源于stack exchange,提问作者ibtissam elhammoumy
相关产品推荐
相关产品推荐

