启用JS Defer后jQuery Ajax触发整页重载,如何解决该问题?
嘿,咱们来理清楚问题的核心:给jQuery脚本加上defer属性后,脚本会等到整个DOM树完全构建完成才会执行,这和原来同步加载脚本(加载时阻塞DOM解析)的执行时机完全不一样。如果你的表单提交事件绑定代码没适配这个新的时机,就会导致jQuery的阻止默认提交逻辑失效,表单触发了浏览器默认的整页提交行为。
常见问题原因及修复方案
1. 内联脚本在jQuery加载前就执行了
如果你的页面里有这样的内联代码(放在带defer的jQuery脚本之前):
$('form').on('submit', function(e) { e.preventDefault(); // 你的Ajax逻辑 });
这段代码执行的时候,jQuery还没被加载(因为defer要等DOM加载完才会加载并执行jQuery),所以代码会直接报错$ is not defined,事件绑定完全失败,表单自然就会走默认的整页提交流程。
修复办法:
把所有依赖jQuery的代码都包裹到$(document).ready()回调里(或者简写的$(function(){...})),或者把这些代码放到单独的脚本文件中,确保这个脚本在jQuery之后加载,并且也加上defer属性:
$(function() { // 等价于$(document).ready(),确保DOM和jQuery都就绪后再执行 $('form').on('submit', function(e) { e.preventDefault(); // 阻止表单默认提交行为 // 你的Ajax请求逻辑示例 $.ajax({ url: $(this).attr('action'), method: $(this).attr('method'), data: $(this).serialize(), success: function(response) { // 处理请求成功后的逻辑 console.log('请求成功:', response); }, error: function(xhr) { // 处理请求失败的情况 console.error('请求失败:', xhr); } }); }); });
2. 动态生成的表单没用到事件委托
如果你的表单是页面加载完成后才动态生成的(比如通过其他Ajax请求加载的内容),直接给表单元素绑定submit事件会失效——因为绑定事件的时候,这个表单元素还不存在于DOM中。
修复办法:
使用事件委托,把事件绑定到一个页面加载时就存在的父级元素上(比如document或者固定的容器元素):
$(function() { // 把事件委托给document,确保动态生成的表单也能触发事件 $(document).on('submit', 'form', function(e) { e.preventDefault(); // 你的Ajax逻辑 }); });
3. 脚本加载顺序出问题了
要确保你的自定义脚本(包含Ajax逻辑)是在jQuery、jquery.validate、jquery.validate.unobtrusive之后加载的,并且同样加上defer属性——这样浏览器会按顺序执行这些defer脚本,不会出现依赖未加载的情况:
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous" defer></script> <script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.16.0/jquery.validate.min.js" defer></script> <script src="https://ajax.aspnetcdn.com/ajax/jquery.validation.unobtrusive/3.2.6/jquery.validate.unobtrusive.min.js" defer></script> <!-- 自定义脚本放在最后,同样加defer --> <script src="/path/to/your/custom-script.js" defer></script>
快速排查小技巧
打开浏览器开发者工具(按F12),切换到「控制台」标签,看看有没有$ is not defined这类错误——如果有,那基本就是jQuery还没加载就执行了依赖它的代码,这就是问题的根源。
内容的提问来源于stack exchange,提问作者Josh

