
在单页应用中,表单默认提交会触发完整页面刷新或导航,即使已绑定 javascript 处理函数并返回 `false`,仍可能因事件绑定时机或执行顺序问题导致路由变更;正确做法是显式调用 `event.preventdefault()`。
当您为 <form> 元素设置 onsubmit="send_mail()" 或通过 document.querySelector('#compose-form').onsubmit = send_mail 绑定处理函数时,浏览器会在表单提交前同步触发该函数,但关键点在于:仅靠 return false 并不能可靠阻止默认行为,尤其在以下情况下:
- 函数未被正确传入事件对象(如 onsubmit = send_mail 不带参数,event 为 undefined);
- return false 在旧式内联绑定中虽可阻止默认行为和冒泡,但在现代事件监听器中语义不明确,且易受执行上下文影响;
- 您当前的 send_mail 函数并未接收 event 参数,因此 event.preventDefault() 无法调用,return false 也因作用域或绑定方式失效。
✅ 正确解决方案是使用标准事件监听器,并在函数首行调用 event.preventDefault():
// 替换原来的:document.querySelector('#compose-form').onsubmit = send_mail;
document.querySelector('#compose-form').addEventListener('submit', function(event) {
event.preventDefault(); // ✅ 关键:立即阻止默认提交行为
const recipients = document.querySelector('#compose-recipients').value;
const subject = document.querySelector('#compose-subject').value;
const body = document.querySelector('#compose-body').value;
fetch('/emails', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ recipients, subject, body })
})
.then(response => response.json())
.then(result => {
console.log('Email sent:', result);
load_mailbox('sent');
})
.catch(error => {
console.error('Failed to send email:', error);
});
});⚠️ 注意事项:
- 不要省略 headers: { 'Content-Type': 'application/json' } —— Django 等后端通常依赖此头解析 JSON 请求体;
- 避免混用 onsubmit= 属性与 addEventListener,推荐统一使用后者,更可控、可移除、符合现代实践;
- return false 在箭头函数或非直接 onsubmit= 场景下不具备阻止默认行为的能力,它仅等价于 event.stopPropagation() + event.preventDefault() 在传统 onclick 等场景中,但对 submit 事件不可靠;
- 若需兼容旧代码,也可保留 onsubmit 赋值,但必须确保函数签名接收 event 并显式调用 preventDefault():
function send_mail(event) {
event.preventDefault(); // ✅ 必须存在
// ...其余逻辑
}
document.querySelector('#compose-form').onsubmit = send_mail;总结:表单路由跳转的根本原因是浏览器默认提交行为未被显式阻止。event.preventDefault() 是标准、可靠、语义明确的解决方式,应始终作为表单 AJAX 提交处理函数的第一行代码。


















