在navigatorBuilder中实现导航组件后,Go Router无法正常导航
问题描述
使用go_router插件实现页面跳转时,点击导航菜单无任何反应,但手动修改URL可以正常切换页面。期望点击导航项时,URL和页面能同步变化。
代码片段
app_router.dart
class AppRouter { AppRouter(this._appBloc); final AppBloc _appBloc; GoRouter get router => GoRouter( routes: pages.values.toList(growable: false), errorBuilder: (context, state) => ErrorPage( key: state.pageKey, ), refreshListenable: GoRouterRefreshStream(_appBloc.stream), navigatorBuilder: _buildRouterView, redirect: _redirect, ); String? _redirect(GoRouterState state) { final loggedIn = _appBloc.state.status == AppStatus.authenticated; final name = state.subloc; final loggingIn = name == '/login' || name == '/'; if (!loggedIn) return loggingIn ? null : '/login'; if (loggingIn) return '/app'; return null; } static Map<String, GoRoute> pages = { route_names.onboard: GoRoute( name: route_names.onboard, path: routes[route_names.onboard]!, pageBuilder: (context, state) => OnboardPage.page(key: state.pageKey), routes: [ GoRoute( path: route_names.login.subRoutePath, name: route_names.login, pageBuilder: (context, state) => LoginPage.page(key: state.pageKey), ), GoRoute( path: route_names.signUp.subRoutePath, name: route_names.signUp, pageBuilder: (context, state) => LoginPage.page(key: state.pageKey), ), ], ), 'app': GoRoute( path: '/app', // All /app pages get the main scaffold builder: (context, state) { return Text("App Main"); }, routes: [ ExplorePage.route, PlanPage.route, AccountPage.route, ]), }; Widget _buildRouterView(BuildContext context, GoRouterState state, Widget child) { return Builder( builder: (context) => BlocBuilder<AppBloc, AppState>(builder: (context, appState) { if (appState.status == AppStatus.unauthenticated) { return child; } return HomePageSkeleton( child: child, ); }), ); } }
app.dart
class AppView extends StatelessWidget { // ignore: prefer_const_constructors_in_immutables AppView({super.key, required AppBloc appBloc}) { _appBloc = appBloc; _appRouter = AppRouter(_appBloc); } late final AppBloc _appBloc; late final AppRouter _appRouter; @override Widget build(BuildContext context) { return BlocListener<AppBloc, AppState>( listener: (context, state) { if (state == const AppState.unauthenticated()) { _appRouter.router.goNamed(route_names.login); } }, child: MaterialApp.router( supportedLocales: AppLocalizations.supportedLocales, routeInformationParser: _appRouter.router.routeInformationParser, routeInformationProvider: _appRouter.router.routeInformationProvider, routerDelegate: _appRouter.router.routerDelegate, ), ); } }
HomePageSkeleton.dart
// inside build method class HomePageSkeleton extends StatelessWidget with NavigationMixin { const HomePageSkeleton({Key? key,required this.child}) : super(key: key); final Widget child; @override Widget build(BuildContext context) { return Scaffold( bottomNavigationBar: Responsive.isMobile(context) ? AppBottomNavigation(index: 0) : const SizedBox(), body: SafeArea( child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (Responsive.isTablet(context) || Responsive.isLaptop(context)) // It takes 1/6 part of the screen Expanded( child: SideMenu(index: 0, onSelected: (index) => onTabSelected(index, context)), ), Expanded( // It takes 5/6 part of the screen flex: 5, child: child), ], ), ), ); } }
onTapSelected方法
//onTapSelected method void onTabSelected(int index, BuildContext context) { switch (index) { case 0: // context.goNamed(route_names.explore); context.go('/app/explore'); break; case 1: // context.goNamed(route_names.plan); context.go('/app/plan'); break; case 2: // context.goNamed(route_names.account); context.go('/app/account'); break; default: throw Exception('Unknown view'); } }
解决方案
1. 确保导航使用正确的GoRouter实例
点击无反应大概率是当前context未关联到GoRouter。替换context.go为直接调用GoRouter实例的方式执行跳转:
void onTabSelected(int index, BuildContext context) { final router = GoRouter.of(context); switch (index) { case 0: router.go('/app/explore'); break; case 1: router.go('/app/plan'); break; case 2: router.go('/app/account'); break; default: throw Exception('Unknown view'); } }
2. 同步导航栏选中状态与当前路由
当前导航栏的index硬编码为0,即使页面跳转,选中状态也不会更新。修改HomePageSkeleton,根据当前路由动态计算选中索引:
@override Widget build(BuildContext context) { // 获取当前路由路径 final currentLocation = GoRouter.of(context).location; // 根据路径匹配选中索引 int currentIndex = 0; if (currentLocation.contains('/plan')) { currentIndex = 1; } else if (currentLocation.contains('/account')) { currentIndex = 2; } return Scaffold( bottomNavigationBar: Responsive.isMobile(context) ? AppBottomNavigation(index: currentIndex) : const SizedBox(), body: SafeArea( child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (Responsive.isTablet(context) || Responsive.isLaptop(context)) Expanded( child: SideMenu( index: currentIndex, onSelected: (index) => onTabSelected(index, context) ), ), Expanded(flex: 5, child: child), ], ), ), ); }
3. 验证子路由配置正确性
确保ExplorePage.route、PlanPage.route、AccountPage.route的路径配置为相对路径(父路由为/app),示例如下:
// ExplorePage的路由配置示例 static GoRoute get route => GoRoute( name: route_names.explore, path: 'explore', // 完整路径为/app/explore pageBuilder: (context, state) => ExplorePage(pageKey: state.pageKey), );
通过以上调整,点击导航项时即可触发URL跳转和页面切换,同时导航栏选中状态也会同步更新。
内容的提问来源于stack exchange,提问作者user19560357
相关产品推荐
相关产品推荐

