Flutter 中如何在用户离开当前屏幕时触发指定函数
全导航场景覆盖的离屏逻辑触发实现
为什么常规方案总会漏场景
很多人第一反应是把离屏逻辑写在组件卸载钩子或者页面的beforeunload事件里,这种写法对应用内向前跳转的场景覆盖没问题,但对pop返回的场景经常失效:一方面移动端WebView的pop动作经常会把页面保活在路由栈里,根本不会触发组件销毁流程;另一方面pop触发的路由切换,很多时候不会走单页应用常规的导航事件链,最后就导致两类场景的触发逻辑对不上,总有一个跑不通。
可落地的实现步骤
核心思路是不要依赖单页面的零散生命周期,直接抓路由栈变更的统一入口——不管是pop回退还是前进跳转,本质都是路由栈的位置变动,一定会触发统一的导航流程,在这个流程里做判断就能100%覆盖两类场景。
- 第一步:给当前激活页面打专属标识
页面挂载完成时,给当前页面对应的路由对象绑定一个激活标记,用来后续导航触发时精准识别“这是不是我们要监听的离屏页面”,避免把其他页面的导航逻辑混进来。比如用Vue路由的场景下,可以在页面挂载钩子里写:// 页面挂载完成后给当前路由加激活标记 const currentRoute = this.$route currentRoute.meta.isPageActive = true - 第二步:在全局导航拦截里统一触发离屏逻辑
全局导航守卫的入参里,from永远对应你即将离开的页面对象,根本不需要额外区分用户是点了返回pop,还是点了按钮前进跳转。只要判断from是不是我们打了激活标记的页面,就可以直接触发自定义离屏逻辑,触发完及时清掉标记避免重复执行。示例代码:router.beforeEach((to, from, next) => { // 校验是不是当前要监听的离屏页面 if (from.meta.isPageActive) { // 在这里替换成你需要的逻辑:调用自定义函数、触发本地离屏通知、离屏埋点都可以 triggerCustomLeaveHandler() // 清除激活标记,避免同一次导航多次触发逻辑 from.meta.isPageActive = false } next() }) - 第三步:补移动端pop场景的兼容兜底
部分老版本WebView或者特殊系统环境下,pop动作的触发不会走到常规的全局导航守卫,这时候需要补两个轻量监听做兜底:- 监听浏览器原生
popstate事件,当检测到路由栈位置已经离开当前页面时,和已有的导航守卫逻辑做去重判断 - 监听
visibilitychange事件,当页面因为pop跳转被隐藏时,复用同一套离屏触发逻辑,不要重复开发
- 监听浏览器原生
必避的常见坑
- 别把离屏逻辑写在组件卸载钩子里:pop场景下的页面大多会被路由缓存保活,根本不会触发卸载流程,写在这里大概率失效
- 一定要做触发去重:一次导航动作可能连续触发多个系统事件/路由守卫,加个简单的状态锁判断,避免自定义函数被重复调用
- 本地离屏通知要提前申请权限:别等触发逻辑的时候才发现用户没给通知权限,最后通知发不出去
补充:如果你用的是Flutter这类跨端开发框架,逻辑是完全通用的——直接复用
RouteObserver的两个回调:didPopNext(pop离开的场景)、didPushNext(前进跳转离开的场景),就能统一触发逻辑,根本不用拆成两套写。
内容的提问来源于stack exchange,提问作者Shrijal Shrestha
相关产品推荐
相关产品推荐

