Next.js如何在用户离开页面时触发自定义函数?
问题原因
浏览器出于安全策略限制,禁止在beforeunload事件回调中调用alert、confirm、prompt等弹窗类API,你遇到的拦截报错是浏览器的强制行为,没有绕过方案。
完整实现方案
你需要分开处理浏览器级别的页面离开和Next.js内部路由跳转离开两种场景,你的代码里之前忽略的routeChangeStart事件正是用来处理内部路由跳转的核心逻辑:
1. 工具逻辑(适配你的catch-all路由)
直接用Next.js内置的useRouter拿聊天室ID,不用单独封装getChatRoomId:
import { useRouter } from 'next/router' import { useEffect } from 'react' import Router from 'next/router' // 组件内获取路由参数 const router = useRouter() // [...messages]的第一个参数就是聊天室ID或者'new' const chatRoomId = router.query.messages?.[0]
2. 完整监听逻辑
useEffect(() => { if (!chatRoomId) return console.log('----HAS ENTERED /messages/* ------', chatRoomId) // 处理浏览器级别的离开:关闭页面、刷新页面、跳转到外部站点 const beforeunload = (e) => { // 不需要用户交互的逻辑直接执行:比如日志上报、状态同步 console.log(`---- IS LEAVING /messages/${chatRoomId} ------`) // 异步上报请求优先用navigator.sendBeacon,不会被浏览器拦截 // navigator.sendBeacon('/api/chat/leave', JSON.stringify({ id: chatRoomId })) // 若需要弹确认框提示用户,用标准写法,浏览器会弹自带的确认弹窗 e.preventDefault() e.returnValue = '确定要离开聊天室吗?未保存的内容将会丢失' return e.returnValue } // 处理Next.js内部路由跳转的离开:点击站内链接跳转到其他页面 const routeChangeStart = (targetUrl) => { // 这里不受beforeunload限制,可以执行任意自定义逻辑:弹自定义弹窗、调用接口等 console.log(`---- 正在跳转到站内页面 ${targetUrl},离开聊天室 ${chatRoomId} ------`) // 若需要拦截跳转做用户确认,可以用以下逻辑终止跳转,用户确认后再手动调用Router.push(targetUrl) // Router.events.emit('routeChangeError') // throw new Error('路由跳转已终止') } window.addEventListener('beforeunload', beforeunload) Router.events.on('routeChangeStart', routeChangeStart) return () => { window.removeEventListener('beforeunload', beforeunload) Router.events.off('routeChangeStart', routeChangeStart) } }, [chatRoomId])
注意事项
- 新浏览器中
beforeunload返回的自定义提示文案不会生效,只会显示浏览器默认的确认提示,属于正常现象 - 若不需要拦截用户离开行为,只是要触发执行指定逻辑,去掉
beforeunload里的e.preventDefault和return相关代码即可
内容的提问来源于stack exchange,提问作者Sylar
相关产品推荐
相关产品推荐

