在Thymeleaf片段中使用$(document).ready函数报错:$未定义
我来帮你解决这个问题——你遇到的$ is not defined错误本质是脚本加载顺序的问题,不需要每次都在主页面直接引入片段的JS,有几个可行的解决办法:
核心原因
你的fragment.js里用了jQuery的$(document).ready,但浏览器加载这个脚本时,jQuery还没被加载完成(要么jQuery的引入在片段脚本之后,要么还没解析完成),所以找不到$这个全局变量。
方法1:确保jQuery在所有依赖脚本之前加载
这是最简单直接的方案。你只需要把jQuery的引入放在页面中早于Thymeleaf片段的位置,确保fragment.js加载时jQuery已经可用:
<!-- pageIncludingFragment.html 中先加载jQuery --> <script th:src="@{/resources/js/jquery.min.js}"></script> <!-- 再引入Thymeleaf片段 --> <div th:include="fragment :: fragment"></div>
不管是把jQuery放在<head>里(记得加defer属性确保DOM解析完成再执行),还是放在页面底部但在片段之前,只要保证加载顺序正确,问题就解决了。
方法2:改用原生JS的DOM加载事件,摆脱jQuery依赖
如果不想调整jQuery的加载位置,你可以把fragment.js里的代码改成原生JS实现,完全不依赖jQuery:
// fragment.js 替换原来的$(document).ready document.addEventListener('DOMContentLoaded', function() { // 这里写你原来的业务逻辑 });
DOMContentLoaded是浏览器原生的事件,和jQuery的$(document).ready效果一致,不需要依赖任何库,自然不会出现$未定义的问题。
方法3:用Thymeleaf布局方言统一管理脚本(进阶方案)
如果你项目里用了Thymeleaf Layout Dialect,可以通过布局的脚本片段来统一控制加载顺序,让所有依赖jQuery的脚本都自动排在jQuery之后:
- 主布局页面(比如
layout.html):
<!DOCTYPE html> <html> <body> <!-- 页面内容占位 --> <div layout:fragment="content"></div> <!-- 先加载jQuery --> <script th:src="@{/resources/js/jquery.min.js}"></script> <!-- 预留的脚本块,供片段插入依赖脚本 --> <div layout:fragment="scripts"></div> </body> </html>
- 主页面
pageIncludingFragment.html:
<html layout:decorate="~{layout}"> <div layout:fragment="content"> <!-- 引入片段 --> <div th:include="fragment :: fragment"></div> </div> </html>
- 片段
fragment.html:
<div th:fragment="fragment"> <!-- 片段的HTML内容 --> ... <!-- 将脚本插入到布局的scripts块中 --> <th:block layout:fragment="scripts"> <script th:src="@{/resources/js/fragment.js}"></script> </th:block> </div>
这样所有片段的脚本都会被自动放到jQuery之后加载,完美解决依赖顺序问题,还能让代码结构更清晰。
总结一下:你完全不需要每次都在主页面直接引入fragment.js,只要处理好脚本的加载顺序,或者改用原生JS事件,就能解决这个错误。
内容的提问来源于stack exchange,提问作者Philipp Poropat

