如何在自定义MVC架构的外部JS文件中使用Twig变量
嘿,我来帮你搞定这个问题~外部JS文件没法直接读取Twig模板里的server_ID变量,原因很简单:Twig是在服务器端渲染模板的,而JS是在浏览器里执行的,两者运行环境完全分开,所以直接在dashboard.js里写{{ server_ID }}肯定会失效,浏览器只会把它当成普通字符串处理。
这里有几个简单又靠谱的解决方案,你可以根据自己的习惯选:
方案1:用HTML的data属性传递变量
这种方式很干净,把变量存在页面的某个元素里,再让JS去读取:
- 在你的
dashboard/get.html模板(就是{% block content %}里的内容)中,添加一个隐藏元素来存储server_ID:
{# 隐藏的div,专门存数据 #} <div id="server-info" data-server-id="{{ server_ID }}" style="display: none;"></div>
或者更省事,直接把属性加在body标签上(如果你的main.html允许修改的话):
<body data-server-id="{{ server_ID }}">
- 修改
dashboard.js,读取这个data属性的值:
function getStats() { var rStart = Date.now(); // 从隐藏元素读取serverID const serverId = document.getElementById('server-info').dataset.serverId; // 如果是存在body上的话,就用这个:document.body.dataset.serverId; $.getJSON("http://localhost/site/public/dashboard/ajax_getstats/" + serverId, function(data) { // 你的处理逻辑 }); } $(document).ready(function() { getStats(); });
方案2:在模板中定义全局JS变量
这个方法更直接,在引入外部JS之前,先在模板里输出一个全局变量,让外部JS可以直接引用:
- 修改
scripts.html,在引入dashboard.js之前,添加一段脚本定义全局变量:
<!-- Optional JavaScript --> <script src="{{ ASSET_ROOT }}/assets/vendor/jquery/jquery-3.3.1.min.js"></script> <script src="{{ ASSET_ROOT }}/assets/vendor/bootstrap/js/bootstrap.bundle.js"></script> {# 先定义全局变量,确保在dashboard.js之前加载 #} <script> window.serverId = "{{ server_ID }}"; </script> <script src="{{ ASSET_ROOT }}/assets/js/dashboard.js"></script>
⚠️ 注意:要保证server_ID变量在scripts.html的渲染上下文中是可用的——因为你的控制器已经把变量传给了dashboard/get模板,而scripts.html是被main.html包含的,所以这个变量是可以正常访问的。
- 在
dashboard.js里直接使用这个全局变量:
function getStats() { var rStart = Date.now(); $.getJSON("http://localhost/site/public/dashboard/ajax_getstats/" + window.serverId, function(data) { // 你的处理逻辑 }); } $(document).ready(function() { getStats(); });
方案3:(进阶)用Twig生成完整的Ajax请求URL
如果你的MVC框架支持路由URL生成(比如类似Symfony的path()或url()函数),你可以直接在模板里生成完整的Ajax请求地址,这样就不用拼接ID了,更安全也更灵活:
- 在
scripts.html里生成全局的URL变量:
<script> // 假设你的路由命名为dashboard_ajax_getstats,并且接受server_ID参数 window.getStatsUrl = "{{ url('dashboard_ajax_getstats', {'server_ID': server_ID}) }}"; </script>
- 在
dashboard.js里直接使用这个URL:
function getStats() { var rStart = Date.now(); $.getJSON(window.getStatsUrl, function(data) { // 你的处理逻辑 }); } $(document).ready(function() { getStats(); });
这个方案的好处是不用硬写URL路径,以后路由结构变了也不用改JS代码,不过需要你的MVC架构支持路由生成功能。
为啥原来的写法不行?
再啰嗦一句:外部JS文件(比如dashboard.js)是浏览器直接请求的静态资源,服务器不会用Twig去解析它(除非你特意配置,但这会影响性能,不推荐),所以{{ server_ID }}会被原封不动地发送给浏览器,JS执行时会把它当成语法错误,自然就失效了。
另外,不用担心安全问题:Twig默认会自动转义变量,所以{{ server_ID }}输出的内容是经过转义的,不会有XSS风险。
内容的提问来源于stack exchange,提问作者rachidsevran

