
使用 preventDefault() 时,若事件监听器在动态注入的 HTML 上绑定过早(DOM 尚未就绪),会导致绑定失败、表单仍按默认方式提交,从而在 URL 中插入 ? 并触发页面跳转。核心在于确保事件委托或绑定时机正确。
使用 `preventdefault()` 时,若事件监听器在动态注入的 html 上绑定过早(dom 尚未就绪),会导致绑定失败、表单仍按默认方式提交,从而在 url 中插入 `?` 并触发页面跳转。核心在于确保事件委托或绑定时机正确。
你遇到的问题——点击提交按钮后 URL 变为 www.webpage.com/?#create,且控制台未输出 "hi"——并非 preventDefault() 失效,而是事件监听器根本未成功绑定。
原因在于:你的表单是通过 $.get() 异步加载到 #app 容器中的(即“动态注入”),而 $("#create-submit").click(...) 在 $(document).ready() 中执行时,该按钮 DOM 节点尚不存在(此时 #app 内容为空)。因此,jQuery 找不到 #create-submit 元素,事件监听器注册失败;后续点击实际触发了 <form> 的原生提交行为,浏览器将空表单以 GET 方式提交,自动在 URL 后追加 ?(表示无查询参数),同时保留原有 hash(如 #create),最终形成 /?#create。
✅ 正确解决方案:使用事件委托(Event Delegation)
由于目标元素(#create-submit)是后期动态插入的,应将事件监听器绑定在始终存在的父级静态容器(如 #app 或 document)上,并指定选择器:
// ✅ 推荐:在 initListener() 中替换原有 click 绑定
$("#app").on("click", "#create-submit", function(e) {
e.preventDefault();
console.log("hi");
});或者更稳妥地绑定到 document(确保全局可用):
$(document).on("click", "#create-submit", function(e) {
e.preventDefault();
console.log("hi");
});⚠️ 注意事项:
- 不要在 $(document).ready() 中直接使用 $("#create-submit").click(...) —— 此时节点未加载,绑定无效;
- 避免重复绑定:若 changeRoute() 可能被多次调用(如 hash 频繁切换),需确保事件委托只注册一次(on() 是安全的,不会重复叠加);
- 若需获取完整表单数据,建议监听 form 的 submit 事件(如答案中所示),语义更准确,且天然支持所有提交方式(回车、按钮点击等):
$("#app").on("submit", "form", function(e) {
e.preventDefault();
console.log("hi");
// 获取数据示例:
const formData = $(this).serialize(); // "fName=John&lName=Doe&email=test%40ex.com..."
console.log("Form data:", formData);
});? 总结:动态内容 + 事件绑定 = 必须用事件委托。$(staticParent).on(event, dynamicSelector, handler) 是处理 AJAX 注入 DOM 的标准实践。坚持使用 preventDefault() 是正确的,但前提是你真的绑定了它——而委托机制确保了这一点。


















