Symfony 4中Javascript函数未定义求助(Symfony Encore场景)
解决Symfony Encore中全局调用JS函数提示「function not defined」的问题
这个问题我之前开发Symfony项目时也踩过坑!核心原因是Symfony Encore基于Webpack打包,默认会把所有JS代码封装在模块的私有作用域里,你定义的openLoginModal函数只存在于这个模块内部,浏览器的全局window对象根本访问不到它,所以模板里的onclick会找不到函数。
下面给你几个可行的解决方案,按推荐程度排序:
方案1:用事件监听替代inline onclick(最推荐,符合现代JS实践)
尽量避免在HTML里写onclick这种内联事件,改用自定义data属性+事件委托的方式,既避免全局污染,代码也更易维护。
步骤:
- 修改模板中的元素,给它加一个自定义data属性:
<!-- 比如原来的按钮 --> <button data-action="open-login-modal">打开登录弹窗</button>
- 在
app.js里添加事件监听(放在$(function(){})里确保DOM加载完成):
/** * Name: app.js * Desc: Main application javascript */ var $ = require('jquery'); require('bootstrap-sass'); require('../css/app.scss'); // Initialize tooltips $(function () { $('[data-toggle="tooltip"]').tooltip(); // 监听自定义data属性的点击事件 $('body').on('click', '[data-action="open-login-modal"]', function() { $('#login-modal').modal('show'); }); });
这里用body做事件委托,就算后续动态添加元素也能生效,比直接绑定元素更灵活。
方案2:将函数暴露到全局window对象(快速临时解决)
如果只是想快速解决问题,可以把函数挂载到全局的window对象上,这样浏览器就能在全局环境找到它:
修改app.js中的函数定义:
var openLoginModal = function(element){ $('#login-modal').modal('show'); } // 把函数暴露到全局window对象 window.openLoginModal = openLoginModal;
之后模板里的onclick="openLoginModal(this)"就能正常工作了。不过这种方式会污染全局命名空间,不推荐在大型项目中大量使用。
方案3:确认Encore打包后的JS已正确引入模板
最后别忘了检查模板里是否正确引入了Encore打包后的JS文件,要确保用Symfony的Twig函数引入:
{# 在模板的底部(</body>标签前)引入 #} {{ encore_entry_script_tags('app') }}
如果JS文件引入位置不对(比如在元素之前加载),就算函数暴露到全局,DOM加载时也会找不到函数,所以尽量把JS放在页面底部。
内容的提问来源于stack exchange,提问作者Adam




