Laravel 8 Blade中Google Pie Chart部署主机后无法显示
本地运行正常、部署后图表空白、无前端报错、后端数据返回完整,这类问题按以下优先级排查即可解决:
1. 最高发原因:Google Charts回调绑定时机错误
你当前用的google.charts.setOnLoadCallback是旧版API,存在触发时序问题:如果Google Charts的loader资源加载完成速度快于你绑定回调的代码执行速度,绘图函数永远不会被触发,也不会抛出任何错误。本地环境因为网络慢、资源加载顺序靠后,绑定操作早于loader加载完成所以能正常运行;线上CDN连接快或者有缓存时,就会出现回调不执行、图表空白的问题。
修复代码:
替换原有JS逻辑,改用官方推荐的Promise式调用,同时修正几个不规范的写法:
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> <script type="text/javascript"> var analytics = {!! json_encode($course) !!}; // 替换旧的setOnLoadCallback写法 google.charts.load('current', {'packages': ['corechart']}).then(drawChart); function drawChart() { const chartDom = document.getElementById('pie_dealer'); if(!chartDom) return; // 提前判断DOM存在,避免元素不存在时静默失败 var data = google.visualization.arrayToDataTable(analytics); var options = { title: 'Presentase Persebaran Dealer GESITS di Indonesia', pieHole: 0.4, // 原代码style字段是无效配置,Google Charts用独立字段配置字体 fontName: 'Open Sans', fontSize: 15, }; var chart = new google.visualization.PieChart(chartDom); chart.draw(data, options); } // 适配窗口大小变化、标签页切换等场景的重绘需求 window.addEventListener('resize', drawChart); </script>
注意:Blade模板中输出JSON不要用
<?php echo ?>直接输出,避免特殊字符被HTML转义导致JS语法错误,使用{!! json_encode() !!}是Laravel官方推荐的传值方式。
2. 次高发原因:CSP策略拦截资源
如果你的线上站点配置了内容安全策略(CSP)响应头,会拦截Google Charts动态加载的绘图包资源,这类拦截通常不会抛出显眼的JS错误,只会导致回调不触发、图表空白。
排查方法:
打开浏览器开发者工具的「网络」面板,筛选JS类型资源,查看是否有来自gstatic.com的资源状态为blocked:csp/已拦截。
修复方法:
在站点CSP配置的脚本加载白名单中添加https://www.gstatic.com即可。
3. 网络连通性问题
如果你的服务面向国内用户,部分网络环境无法正常访问gstatic.com的CDN资源,会出现loader.js加载成功,但后续corechart绘图包加载失败的情况,也会导致空白。这种场景建议把Google Charts的静态资源下载到自有服务器托管,不要调用境外公共CDN。
控制器逻辑优化
你当前构造图表数据的逻辑可以简化,避免手动偏移数组键可能带来的索引问题:
public function index() { $count_dealers = DB::table('dealer_gesits')->count(); $data_dealer = Dealer::select( DB::raw('province as province'), DB::raw('count(*) as number') ) ->groupBy('province') ->get(); // 初始化图表数组,不需要手动维护键值 $array = [['Province', 'Number']]; foreach ($data_dealer as $item) { $array[] = [$item->province, $item->number]; } $dealers = Dealer::query(); if(request('search')){ $dealers->where('dealer_name', 'like', '%'.request('search').'%') ->orWhere('address', 'like', '%'.request('search').'%'); } $dealers = $dealers->paginate(20); $user = Customer::latest()->get(); return view('dashboard.dealer.index', compact('dealers', 'count_dealers','user')) ->with('course', json_encode($array)); }
内容的提问来源于stack exchange,提问作者Caktozz

