Flutter Web中如何用AutoRoute处理浏览器前进后退按钮及路由拦截
解决方案
1. 拦截未登录用户直接访问首页
利用AutoRoute的RouteGuard实现登录状态校验,不管用户是通过URL直接访问还是路由跳转,都会先经过守卫判断:
首先定义登录状态守卫类:
class AuthGuard extends AutoRouteGuard { @override void onNavigation(NavigationResolver resolver, StackRouter router) { // 替换为你实际的登录状态判断逻辑(比如从状态管理或本地存储获取) bool isLoggedIn = AuthService.instance.isLoggedIn; if (isLoggedIn) { // 已登录,允许进入首页 resolver.next(true); } else { // 未登录,拦截并跳转到登录页 router.push(LoginRoute()); resolver.next(false); } } }
然后在AutoRoute的路由配置中,为首页路由添加守卫:
@MaterialAutoRouter( routes: [ AutoRoute(page: LoginPage, initial: true), AutoRoute(page: HomePage, guards: [AuthGuard()]), ], ) class $AppRouter {}
2. 阻止登录后通过浏览器后退返回登录页
由于WillPopScope在Web端无法拦截浏览器原生后退事件,我们结合AutoRoute的路由栈管理+Web端popstate事件监听来解决:
步骤1:登录成功后清除登录页路由
登录完成跳转首页时,使用replace或pushAndRemoveUntil清空路由栈中登录页的记录:
// 登录成功后的跳转逻辑 router.replace(const HomeRoute()); // 或者用pushAndRemoveUntil确保栈中仅保留首页 // router.pushAndRemoveUntil(const HomeRoute(), (route) => false);
步骤2:监听Web端后退事件,防止回退到空栈
在根Widget的initState中添加浏览器后退事件监听,当路由栈仅剩首页时,阻止后退操作:
import 'dart:html' as html; import 'package:flutter/foundation.dart'; class MyApp extends StatefulWidget { const MyApp({super.key}); @override State<MyApp> createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { late final AppRouter _router; StreamSubscription? _popStateSubscription; @override void initState() { super.initState(); _router = AppRouter(); if (kIsWeb) { // 监听浏览器popstate事件 _popStateSubscription = html.window.onPopState.listen((_) { final routeCount = _router.stack.length; if (routeCount <= 1) { // 栈中仅首页,重置历史记录阻止后退 html.window.history.pushState(null, '', html.window.location.href); } }); } } @override void dispose() { _popStateSubscription?.cancel(); super.dispose(); } @override Widget build(BuildContext context) { return MaterialApp.router( routerDelegate: _router.delegate(), routeInformationParser: _router.defaultRouteParser(), ); } }
补充:用RouteObserver加固路由栈校验
添加路由观察者,确保登录后路由栈中无登录页残留:
class AuthRouteObserver extends RouteObserver<PageRoute> { @override void didPush(Route route, Route? previousRoute) { super.didPush(route, route); if (route.settings.name == HomeRoute.name && previousRoute?.settings.name == LoginRoute.name) { // 移除登录页的路由记录 AppRouter.of(context).removeRoute(previousRoute!); } } }
初始化Router时注入观察者:
_router = AppRouter(observers: [AuthRouteObserver()]);
内容的提问来源于stack exchange,提问作者Fuse Koda
相关产品推荐
相关产品推荐

