You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter GoRouter:ShellRoute二级路由跳转默认回到首个主页面问题

解决go_router中ShellRoute下二级路由跳转回到首页的问题

你的问题核心有两个:

  • 所有二级路由只挂载在了Home主路由的子路由列表里,其他三个主路由(Search/Events/Account)下面没有这些二级路由的定义,所以跳转二级路由时,go_router只能匹配到Home下的对应路由,导致自动切回首页。
  • 二级路由设置了parentNavigatorKey: _rootNavigatorKey,这会让页面在根导航器中打开,完全脱离ShellRoute的结构,底部导航栏会被隐藏,同时路由栈也会重置。

步骤1:将二级路由分配到对应主路由下

如果某些二级路由是多个主路由共用的,可以封装成通用子路由列表,然后在每个主路由的routes里引入。修改GoRouter的ShellRoute部分:

ShellRoute(
  navigatorKey: _shellNavigatorKey,
  pageBuilder: (context, state, child) => MaterialPage(
    child: MainScreenWrapper(child: child),
  ),
  routes: [
    // 循环生成所有主路由,每个主路由下都添加对应的子路由
    ...mainScreens.map((mainScreen) {
      final List<RouteBase> childRoutes = [];
      // 添加通用二级路由
      childRoutes.addAll(secondaryScreens.map((screen) => GoRoute(
            path: screen.path,
            name: screen.name,
            pageBuilder: (context, state) => MaterialPage(
              child: screen as Widget,
            ),
          )));
      // 复用你之前的其他子路由配置
      childRoutes.addAll(screensWithPathParams.map((screenEntity) => GoRoute(
            path: screenEntity.path,
            name: screenEntity.name,
            pageBuilder: (context, state) {
              final param = state.pathParameters[screenEntity.paramName];
              return MaterialPage(
                child: screenEntity.build(context, param!),
              );
            },
          )));
      childRoutes.addAll(screensWithParams.map((screenEntity) => GoRoute(
            path: screenEntity.path,
            name: screenEntity.name,
            pageBuilder: (context, state) {
              final extra = state.extra as ScreenProps;
              return MaterialPage(
                child: screenEntity.build(context, extra),
              );
            },
          )));
      // 模态框/对话框类路由保留根导航器配置
      childRoutes.addAll(modalEntities.map((modalEntity) => GoRoute(
            parentNavigatorKey: _rootNavigatorKey,
            path: modalEntity.path,
            name: modalEntity.name,
            pageBuilder: (context, state) => ModalPage(
              isDismissible: modalEntity.isDismissible,
              isScrollControlled: modalEntity.isScrollControlled,
              enableDrag: modalEntity.enableDrag,
              builder: (context) => modalEntity.build(
                context,
                state.extra as ModalProps,
                ref: ref,
              ),
            ),
          )));
      // 继续添加其他类型路由...

      return GoRoute(
        parentNavigatorKey: _shellNavigatorKey,
        path: mainScreen.path,
        name: mainScreen.name,
        pageBuilder: (context, state) {
          return NoTransitionPage(child: mainScreen as Widget);
        },
        routes: childRoutes, // 给每个主路由绑定子路由
      );
    }),
  ],
),

步骤2:调整跳转方式

跳转二级路由时,使用相对路径或者基于当前路由上下文的命名跳转,确保go_router在当前主路由的栈中加载子路由:

  • 相对路径跳转(推荐,无需关心当前主路由):
// 从任意主路由跳转到ScreenUserSettings
context.go('./${ScreenUserSettings().path}');
  • 命名路由跳转(带父路由前缀):
// 获取当前主路由名称,作为父路由前缀
final currentMainRoute = GoRouterState.of(context).matchedLocation.split('/')[1];
context.goNamed(
  ScreenUserSettings().name,
  pathParameters: {},
  parentNavigatorKey: _shellNavigatorKey,
);

步骤3:修正二级路由的NavigatorKey

如果希望二级页面保留底部导航栏,移除二级路由的parentNavigatorKey: _rootNavigatorKey,这样会继承父路由的_shellNavigatorKey,页面在Shell的子导航栈中打开,底部导航栏保持可见。

如果是全屏模态框/对话框,保留parentNavigatorKey: _rootNavigatorKey,确保覆盖整个屏幕。


补充说明

  • 之前只有Home主路由配置了子路由,其他主路由没有,所以跳二级路由时只能匹配到Home的子路由,导致切回首页。
  • context.go()会替换当前路由栈,context.push()会添加新页面到栈中,根据需求选择:需要返回主路由用push(),需要替换当前页面用go()。

内容的提问来源于stack exchange,提问作者Verilyzed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 03:04:51