Flutter Web中Router API(go_router)阻止页面回退的替代方案
Flutter Web未保存更改时阻止页面回退的解决方案
一、go_router环境下的替代方案
由于WillPopScope在Web端go_router中存在兼容性问题,可尝试以下两种方法:
1. 使用PopScope组件(Flutter 3.10+)
PopScope是官方替代WillPopScope的组件,Web端go_router可正常使用。通过它拦截回退请求,结合确认弹窗判断是否允许离开:
PopScope( canPop: false, // 禁用默认回退逻辑 onPopInvoked: (bool didPop) async { if (!didPop) { if (_hasUnsavedChanges) { final shouldPop = await showDialog<bool>( context: context, builder: (_) => AlertDialog( title: const Text('确认离开'), content: const Text('你有未保存的更改,确定要离开吗?'), actions: [ TextButton( onPressed: () => Navigator.pop(context, false), child: const Text('取消'), ), TextButton( onPressed: () => Navigator.pop(context, true), child: const Text('确定'), ), ], ), ); if (shouldPop == true) { context.goBack(); } } else { context.goBack(); } } }, child: // 你的页面内容 )
注意:需确保Flutter版本≥3.10,PopScope才会生效。
2. 直接监听浏览器popstate事件
通过dart:html库监听浏览器回退事件,在有未保存更改时阻止默认行为:
import 'dart:html' as html; @override void initState() { super.initState(); html.window.addEventListener('popstate', _handleBackPress); } @override void dispose() { html.window.removeEventListener('popstate', _handleBackPress); super.dispose(); } void _handleBackPress(html.Event event) { if (_hasUnsavedChanges) { event.preventDefault(); // 阻止默认回退 showDialog( context: context, builder: (_) => AlertDialog( title: const Text('确认离开'), content: const Text('你有未保存的更改,确定要离开吗?'), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('取消'), ), TextButton( onPressed: () { Navigator.pop(context); context.goBack(); // 用户确认后手动回退 }, child: const Text('确定'), ), ], ), ); } }
这种方式绕开Flutter路由层,直接对接浏览器原生事件,不受go_router的兼容问题影响。
二、使用auto_route实现回退拦截
auto_route内置路由守卫机制,可轻松实现未保存更改的回退拦截,步骤如下:
1. 定义自定义路由守卫
创建守卫类,拦截回退动作并检查未保存状态:
class UnsavedChangesGuard extends AutoRouteGuard { final bool Function() hasUnsavedChanges; final BuildContext context; UnsavedChangesGuard({required this.hasUnsavedChanges, required this.context}); @override void onNavigation(NavigationResolver resolver, StackRouter router) async { if (resolver.isBackNavigation && hasUnsavedChanges()) { final shouldLeave = await showDialog<bool>( context: context, builder: (_) => AlertDialog( title: const Text('确认离开'), content: const Text('你有未保存的更改,确定要离开吗?'), actions: [ TextButton( onPressed: () => Navigator.pop(context, false), child: const Text('取消'), ), TextButton( onPressed: () => Navigator.pop(context, true), child: const Text('确定'), ), ], ), ); resolver.next(shouldLeave == true); } else { resolver.next(true); } } }
2. 为目标页面绑定守卫
在auto_route的路由配置中,给需要拦截的页面添加守卫:
@MaterialAutoRouter( routes: [ AutoRoute(page: HomePage), AutoRoute( page: EditPage, guards: [UnsavedChangesGuard], // 绑定守卫 ), ], ) class $AppRouter {}
3. 在页面中初始化守卫
在编辑页面中,注册守卫并传入未保存状态的判断逻辑:
class EditPage extends StatefulWidget { const EditPage({super.key}); @override State<EditPage> createState() => _EditPageState(); } class _EditPageState extends State<EditPage> { bool _hasUnsavedChanges = false; @override Widget build(BuildContext context) { final routeData = AutoRouteData.of(context); routeData.registerGuard(UnsavedChangesGuard( hasUnsavedChanges: () => _hasUnsavedChanges, context: context, )); return Scaffold( body: TextField( onChanged: (_) => setState(() => _hasUnsavedChanges = true), ), ); } }
用户尝试回退时,守卫会自动触发检查,根据用户选择决定是否允许导航。
内容的提问来源于stack exchange,提问作者Abigotado
相关产品推荐
相关产品推荐

