无需登录 数据私有 本地保存

beforeunload 事件演示 - 页面离开确认对话框

1
0
0
0
保护已关闭
beforeunload 监听未激活
启用离开保护
模拟编辑表单
未保存更改
注意:您有未保存的更改。离开页面时浏览器将弹出确认对话框。
事件监控面板
0
触发次数
0
用户留下
0
总交互
事件日志
暂无日志记录
启用保护并编辑内容后开始监测
测试操作区

以下按钮将触发页面导航或刷新,如果保护已激活且有未保存更改,浏览器将弹出确认对话框。

外部链接 (example.com)
离开站点?
您所做的更改可能不会保存。
Chrome 浏览器典型对话框预览(不同浏览器外观略有差异)
Chrome

需要用户手势交互;自定义消息被忽略;显示通用确认对话框。

Firefox

行为与Chrome类似;需要用户交互;忽略自定义消息。

Safari

桌面端支持良好;iOS移动端行为可能不一致。

Edge

基于Chromium,行为与Chrome完全一致。

常见问题与知识点

beforeunload 事件在浏览器窗口、文档或其资源即将卸载时触发。常见触发场景包括:关闭标签页、刷新页面、点击链接导航离开、提交表单跳转、使用前进/后退按钮导航等。该事件允许开发者在用户离开页面前弹出确认对话框,常用于防止用户意外丢失未保存的数据。

Chrome 51+、Firefox 44+、Safari 9.1+ 开始,浏览器为了安全和防滥用,不再显示网站设置的自定义消息,而是使用浏览器自身的通用提示文案(如"您所做的更改可能不会保存")。即使你在 event.returnValue 或返回值中设置了自定义文本,浏览器也会忽略它。设置空字符串即可触发对话框。

常见原因:
没有用户手势交互——现代浏览器要求用户必须与页面进行了实际交互(点击、输入、滚动等),beforeunload对话框才会显示。如果页面刚加载用户就尝试关闭,对话框不会弹出。
在iframe中——跨域iframe中的beforeunload行为受限制。
移动端浏览器——iOS Safari在切换标签时可能不触发。
开发者工具打开——某些调试模式下行为可能不同。

特性beforeunloadunload
可取消性✅ 可取消(弹出对话框)❌ 不可取消
用途询问用户是否离开清理资源、发送分析数据
异步操作受限受限(推荐用sendBeacon)
触发时机卸载前卸载时
自定义消息旧浏览器支持不适用

添加监听:
window.addEventListener('beforeunload', handler);

移除监听:
window.removeEventListener('beforeunload', handler);

⚠️ 注意:必须传入相同的函数引用才能成功移除。使用匿名函数或箭头函数直接写在addEventListener中会导致无法移除。推荐将handler定义为命名函数或保存在变量中。

条件触发模式:在handler内部检查条件标志,而不是频繁添加/移除监听器,这样更简洁可靠。

移动端支持情况较为复杂:
Android Chrome:支持良好,需要用户手势。
iOS Safari:支持有限。关闭标签页或切换应用通常不会触发beforeunload;导航离开时通常会触发。
PWA应用:行为取决于浏览器和操作系统。
移动端微信/支付宝内置浏览器:支持情况不一,建议实际测试。
建议在移动端同时监听 visibilitychangepagehide 事件作为补充。

最佳实践:
• 仅在用户有未保存更改时才激活beforeunload,避免滥用。
• 使用条件标志控制,而非频繁绑定/解绑事件。
• 结合自动保存功能,减少用户数据丢失风险。
• 在SPA中使用路由守卫(如React Router的useBlocker、Vue Router的beforeRouteLeave)。

替代方案:
navigator.sendBeacon()——在unload中可靠发送数据。
localStorage/sessionStorage——实时保存草稿。
IndexedDB——存储较大的未保存数据。
WebSocket断开时自动保存——服务端感知用户离开。

在SPA(React、Vue、Angular等)中,路由切换不会触发原生的beforeunload事件(因为页面没有真正卸载)。你需要使用框架提供的路由守卫:

React Router v6:使用 useBlocker hook。
Vue Router:使用 beforeRouteLeave 导航守卫。
Angular:使用 CanDeactivate 路由守卫接口。

同时保留原生的beforeunload监听来处理关闭标签页和刷新场景,两者结合才能覆盖所有离开路径。