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

如何使用参数化路由作为GoRoute中StatefulShellRoute的根路由

解决GoRouter StatefulShellBranch参数化路由错误的方案

你遇到的错误是因为StatefulShellBranch的默认路由(分支内第一个路由)不允许带路径参数,调整路由层级结构就能解决这个问题。正确的思路是把参数化的/:id路由作为父级,在它内部嵌套StatefulShellRoute,让三个标签页的路由作为分支的默认无参数路由,既符合GoRouter规则,又能实现你需要的URL结构和有状态导航。

修改后的路由配置代码

final GlobalKey<NavigatorState> _rootNavigatorKey = GlobalKey<NavigatorState>();
final GlobalKey<NavigatorState> _pageANavigatorKey = GlobalKey<NavigatorState>();
final GlobalKey<NavigatorState> _pageBNavigatorKey = GlobalKey<NavigatorState>();
final GlobalKey<NavigatorState> _pageCNavigatorKey = GlobalKey<NavigatorState>();

final GoRouter _router = GoRouter(
  navigatorKey: _rootNavigatorKey,
  routes: <RouteBase>[
    GoRoute(
      path: '/',
      builder: (BuildContext context, GoRouterState state) {
        return const MyHomePage();
      },
      routes: [
        GoRoute(
          path: 'foo',
          builder: (BuildContext context, GoRouterState state) {
            return const FooListScreen();
          },
          routes: [
            // 参数化:id作为父路由,内部嵌套StatefulShellRoute
            GoRoute(
              name: "fooDetails",
              path: ":id",
              builder: (context, state) {
                return StatefulShellRoute.indexedStack(
                  builder: (context, state, navigationShell) {
                    return Scaffold(
                      body: navigationShell,
                      bottomNavigationBar: BottomNavigationBar(
                        currentIndex: navigationShell.currentIndex,
                        onTap: (index) {
                          navigationShell.goBranch(
                            index,
                            initialLocation: index == navigationShell.currentIndex,
                          );
                        },
                        items: const [
                          BottomNavigationBarItem(icon: Icon(Icons.pageview), label: 'Page A'),
                          BottomNavigationBarItem(icon: Icons.pages, label: 'Page B'),
                          BottomNavigationBarItem(icon: Icons.pagination, label: 'Page C'),
                        ],
                      ),
                    );
                  },
                  branches: [
                    StatefulShellBranch(
                      navigatorKey: _pageANavigatorKey,
                      routes: [
                        GoRoute(
                          path: 'pageA',
                          builder: (context, state) {
                            final id = int.parse(state.pathParameters['id'] ?? '0');
                            return FooPageA(id: id);
                          },
                        ),
                      ],
                    ),
                    StatefulShellBranch(
                      navigatorKey: _pageBNavigatorKey,
                      routes: [
                        GoRoute(
                          path: 'pageB',
                          builder: (context, state) {
                            final id = int.parse(state.pathParameters['id'] ?? '0');
                            return FooPageB(id: id);
                          },
                        ),
                      ],
                    ),
                    StatefulShellBranch(
                      navigatorKey: _pageCNavigatorKey,
                      routes: [
                        GoRoute(
                          path: 'pageC',
                          builder: (context, state) {
                            final id = int.parse(state.pathParameters['id'] ?? '0');
                            return FooPageC(id: id);
                          },
                        ),
                      ],
                    ),
                  ],
                ).builder(context, state, null);
              },
              // 进入/foo/:id时自动跳转到第一个标签页
              redirect: (context, state) {
                final id = state.pathParameters['id'];
                if (id != null && state.uri.pathSegments.length == 2) {
                  return '/foo/$id/pageA';
                }
                return null;
              },
            ),
          ],
        ),
      ],
    ),
  ],
);

关键修改点说明

  1. 层级调整:把参数化的/:id路由作为foo的子路由,内部嵌套StatefulShellRoute,让三个标签页路由作为分支的默认无参数路由,避开错误限制。
  2. 参数传递:标签页页面可通过state.pathParameters['id']获取父路由的id参数,GoRouter会自动向上传递路径参数。
  3. 默认跳转:添加redirect逻辑,用户进入/foo/:id时自动跳转到/foo/:id/pageA,确保进入详情页直接显示第一个标签页。
  4. 状态保留:StatefulShellRoute.indexedStack会保持每个标签页的状态,切换时不会重新构建页面,满足有状态导航需求。

列表页跳转示例

在FooListScreen中跳转到详情页:

// 假设选中的foo id为1
context.goNamed('fooDetails', pathParameters: {'id': '1'});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 05:53:18