
本文详解如何将服务端生成的图表数据(如数组、对象)通过 EJS 安全注入前端 JavaScript,解决 ReferenceError: graphs is not defined 问题,并实现动态渲染 Google Charts 图表。
本文详解如何将服务端生成的图表数据(如数组、对象)通过 ejs 安全注入前端 javascript,解决 `referenceerror: graphs is not defined` 问题,并实现动态渲染 google charts 图表。
在 Express + EJS 应用中集成 Google Charts 时,一个常见误区是认为模板变量(如 <%= graphs %>)能直接被浏览器端 JavaScript 访问。实际上,EJS 渲染发生在服务端,而 graphs 是 Node.js 作用域内的变量,不会自动暴露到客户端全局作用域。因此,当 drawGraphs() 尝试访问未声明的 graphs 时,浏览器抛出 ReferenceError。
✅ 正确做法是:在 EJS 模板中使用 <%- JSON.stringify(graphs) %> 将数据序列化为合法的 JavaScript 字面量,并赋值给一个客户端变量。注意必须使用 <%- ... %>(非转义输出),否则 JSON 中的引号会被 HTML 转义(如 " → "),导致语法错误。
以下是修正后的 chart.ejs 关键部分(已优化结构与健壮性):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Google Charts with EJS</title>
<!-- 加载 Google Charts 库 -->
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<!-- ✅ 关键:将 EJS 数据安全注入 JS 变量 -->
<script type="text/javascript">
// 注意:必须使用 <%- ... %> 避免 HTML 转义;JSON.stringify 确保格式合法
const chartData = <%- JSON.stringify(graphs) %>;
// 初始化图表
google.charts.load('current', { packages: ['corechart'] });
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
// 创建容器 DOM 元素
const container = document.body;
const div = document.createElement('div');
div.id = chartData.name;
div.style.cssText = 'width: 1200px; height: 500px; margin: 20px auto;';
container.appendChild(div);
// 构建 DataTable
const data = new google.visualization.DataTable();
data.addColumn('string', 'Toppings');
data.addColumn('number', 'Slices');
data.addRows(chartData.myData); // ✅ 直接使用注入的数据
// 配置选项
const options = {
title: chartData.name,
width: 600,
height: 400,
pieHole: 0.4, // 可选:环形图效果
backgroundColor: '#f9f9f9'
};
// 渲染图表
const chart = new google.visualization.PieChart(div);
chart.draw(data, options);
}
</script>
</head>
<body>
<h1>? 动态 Pizza Topping Dashboard</h1>
<!-- 可选:服务端渲染数据用于调试或 SEO -->
<ul>
<% graphs.myData.forEach(([topping, slices]) => { %>
<li><strong><%= topping %>:</strong> <%= slices %> slice<%= slices !== 1 ? 's' : '' %></li>
<% }) %>
</ul>
</body>
</html>? 重要注意事项:
- 永远不要使用 <%= graphs %>:它会对特殊字符进行 HTML 转义(如 { "name": "A&B" } → { "name": "A&B" }),破坏 JSON 结构;
- 务必使用 <%- JSON.stringify(graphs) %>:<%- 表示“原始输出”,配合 JSON.stringify 可生成严格合规的 JS 对象字面量;
- 数据结构需匹配 Google Charts API:例如 addRows() 接收二维数组,确保 myData 是类似 [["A", 1], ["B", 2]] 的格式;
- 避免 XSS 风险:若 graphs 中包含用户输入内容(如图表标题),应在服务端做白名单过滤或前端渲染时使用 textContent 替代 innerHTML;
- 扩展建议:如需渲染多个图表,可将 graphs 设计为数组(如 [{name: "Chart1", myData: [...]}, ...]),并在 drawChart() 中遍历调用 drawSingleChart(g)。
通过以上方式,你既能保持服务端逻辑清晰(Express 控制数据获取与模板渲染),又能充分发挥 Google Charts 的交互能力,构建真正动态、可维护的数据看板。










