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

使用go_router的ShellRoute实现类Twitter导航的路由配置疑问

问题描述

我希望实现类似Twitter的导航效果:底部导航栏包含首页、搜索两个标签页,首页展示推文列表,点击推文跳转至详情页;搜索页可搜索推文,点击结果同样跳转至详情页。我基于ShellRoute编写了如下路由代码:

// 我用ShellRoute实现了持久化底部导航栏
final GlobalKey<NavigatorState> _rootNavigatorKey =
    GlobalKey<NavigatorState>();

final GoRouter _router = GoRouter(
  navigatorKey: _rootNavigatorKey,
  initialLocation: '/home',
  routes: [
    ShellRoute(
      navigatorKey: _shellNavigatorKey,
      builder: (context, state, child) {
        return ScaffoldWithNavBar(child: child);
      },
      routes: [
        GoRoute(
          path: '/home',
          builder: (context, state) {
            return const Home();
          },
          routes: <RouteBase>[
            GoRoute(
              path: 'details',
              builder: (BuildContext context, GoRouterState state) {
                return const DetailsScreen(tweet_id: 'id');
              },
            ),
          ],
        ),
        GoRoute(
          path: '/search',
          builder: (BuildContext context, GoRouterState state) {
            return const Search();
          },
          routes: <RouteBase>[
            GoRoute(
              path: 'details',
              builder: (BuildContext context, GoRouterState state) {
                return const DetailsScreen(tweet_id: 'id');
              },
            ),
          ],
        ),
      ],
    ],
  ),
);

我的疑问:

  • 当前定义了/home/details和/search/details两个路径指向同一详情页,这种配置是否正确?
  • 是否必须为每个标签页路由都重复定义details子路由?若新增标签页(如书签页),是否也要重复该操作?
  • 我期望当收到/details/<tweet-id>路径时,在当前标签页打开对应推文详情页,该如何配置?
解决方案

1. 当前配置的正确性

你的配置功能上是可行的,但存在冗余问题。虽然两个路径都能正确跳转到详情页,但后续修改详情页的参数或逻辑时,需要在多个同步修改,维护成本更高。

2. 避免重复定义子路由的方法

不需要为每个标签页重复定义details子路由。可以把详情页路由提升到根路由层级,脱离ShellRoute的子路由范围,让所有标签页复用同一个详情页路由。

修改后的路由配置示例:

final GlobalKey<NavigatorState> _rootNavigatorKey = GlobalKey<NavigatorState>();
final GlobalKey<NavigatorState> _shellNavigatorKey = GlobalKey<NavigatorState>();

final GoRouter _router = GoRouter(
  navigatorKey: _rootNavigatorKey,
  initialLocation: '/home',
  routes: [
    ShellRoute(
      navigatorKey: _shellNavigatorKey,
      builder: (context, state, child) {
        return ScaffoldWithNavBar(child: child);
      },
      routes: [
        GoRoute(
          path: '/home',
          builder: (context, state) => const Home(),
        ),
        GoRoute(
          path: '/search',
          builder: (context, state) => const Search(),
        ),
        // 新增书签页时,只需在这里添加一条路由即可,无需重复写details子路由
        GoRoute(
          path: '/bookmarks',
          builder: (context, state) => const Bookmarks(),
        ),
      ],
    ),
    // 独立的详情页路由,所有标签页都能访问
    GoRoute(
      path: '/details/:tweetId',
      builder: (context, state) {
        // 从路由参数中获取tweetId
        final tweetId = state.pathParameters['tweetId']!;
        return DetailsScreen(tweet_id: tweetId);
      },
    ),
  ],
);

配置完成后,不管是首页还是搜索页跳转,直接使用context.go('/details/$tweetId')即可,无需区分当前所在标签页的路径。

3. 处理/details/<tweet-id>路径的跳转需求

上面的配置已经实现了该功能:当收到/details/<tweet-id>路径时,GoRouter会匹配根层级的详情页路由,由于该路由不在ShellRoute的子路由中,它会在当前标签页的导航栈中打开,底部导航栏保持可见,详情页在标签页内容上方叠加。

注意事项:

  • 跳转时要正确传递tweetId参数,例如context.go('/details/123')
  • 在详情页中通过state.pathParameters['tweetId']获取参数值

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 17:53:16