
本文详解 flask 中通过外部 javascript 文件(而非内联 script)加载 chart.js 图表的完整实现方案,解决因模块导入、模板变量传递和执行时机导致的图表不渲染问题。
本文详解 flask 中通过外部 javascript 文件(而非内联 script)加载 chart.js 图表的完整实现方案,解决因模块导入、模板变量传递和执行时机导致的图表不渲染问题。
在 Flask 应用中将 Chart.js 图表逻辑从 HTML 内联脚本迁移到独立的 .js 文件(如 static/js/graph.js)是提升代码可维护性的常见需求。但直接使用 <script type="module"> 导入 CDN 上的 Chart.js 并在外部 JS 中引用 Jinja2 模板变量(如 {{ labels | safe }}),会导致两个关键问题:浏览器 CORS 策略阻止模块跨域加载,以及Jinja2 变量无法在纯 .js 文件中解析(因为 .js 文件由静态服务器直接返回,不经过 Flask 模板引擎)。
✅ 正确做法是:Chart.js 仍通过 <script> 标签在 HTML 中全局引入;外部 JS 文件仅负责初始化图表,并通过安全方式获取后端传入的数据。以下是推荐的三步实践方案:
1. HTML 模板:全局引入 Chart.js,预置数据为全局变量
修改你的 templates/chart.html,移除 type="module",改用传统脚本加载,并将数据挂载到 window 对象:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sample chart</title>
<!-- ✅ 使用普通 script 标签引入 Chart.js(非 module) -->
<script src="https://cdn.jsdelivr.net/npm/chart.js@4"></script>
</head>
<body>
<canvas id="lineChart" width="900" height="400"></canvas>
<!-- ✅ 将后端数据注入全局 JS 变量(必须在 graph.js 之前) -->
<script>
window.chartData = {
labels: {{ labels | tojson }},
values: {{ values | tojson }}
};
</script>
<!-- ✅ 外部 JS 文件使用普通 script(非 module) -->
<script src="{{ url_for('static', filename='js/graph.js') }}"></script>
</body>
</html>⚠️ 关键点:
- 使用 {{ data | tojson }}(而非 | safe)确保 JSON 转义安全,避免 XSS;
- window.chartData 必须在 graph.js 加载前定义,保证其可被访问。
2. 外部 JS 文件:使用原生 JS 初始化图表
static/js/graph.js 内容如下(注意:不 import Chart.js,直接使用全局 Chart 构造函数):
// ✅ 确保 DOM 加载完成后再执行
document.addEventListener('DOMContentLoaded', function () {
const ctx = document.getElementById('lineChart').getContext('2d');
// ✅ 从全局变量读取数据
const { labels, values } = window.chartData;
new Chart(ctx, {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'Data Points',
data: values,
fill: false,
borderColor: 'rgb(75, 192, 192)',
tension: 0.1
}]
},
options: {
responsive: true, // ✅ 建议设为 true 以适配响应式布局
maintainAspectRatio: false
}
});
});3. Flask 后端:正确传递数据(示例路由)
确保视图函数中以 Python 列表/字典形式传参,Jinja2 自动序列化:
# app.py
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/chart')
def show_chart():
# 示例数据(实际中可能来自数据库或 API)
labels = ['Jan', 'Feb', 'Mar', 'Apr', 'May']
values = [12, 19, 3, 5, 2]
return render_template('chart.html', labels=labels, values=values)? 常见错误排查清单
- ❌ 错误:Uncaught TypeError: Chart is not defined → 检查 Chart.js <script> 是否在 graph.js 之前加载;
- ❌ 错误:Cannot read property 'labels' of undefined → 检查 window.chartData 是否正确定义且拼写一致;
- ❌ 图表空白但无报错 → 检查 Canvas 元素是否存在、ID 是否匹配,以及 DOMContentLoaded 是否触发;
- ❌ 数据显示为字符串而非数字 → 确保 values 是数字列表(如 [12, 19]),而非字符串列表(如 ['12', '19'])。
通过以上结构,你既能保持前端逻辑解耦(图表初始化与 HTML 分离),又能规避模块加载限制和模板变量作用域问题,实现稳定、可扩展的 Flask + Chart.js 集成方案。


















