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

使用GoRouter 5.0的ShellRoute切换标签页时如何返回嵌套路由?

问题:GoRouter 5.0结合ShellRoute实现嵌套导航时标签页状态丢失

我正尝试在GoRouter 5.0中结合ShellRoute实现嵌套导航。点击商品时可正确导航至嵌套的商品详情页,但切换到购物车标签页再切回商品标签页时,会回到根级的商品列表页,而非之前停留的商品详情页:

ShellRoute示例(GoRouter 5.0)

路由配置

enum AppRoute {
  products,
  product,
  cart,
  account,
}

final goRouter = GoRouter(
    initialLocation: '/products',
    navigatorKey: _rootNavigatorKey,
    debugLogDiagnostics: true,
    routes: [
      ShellRoute(
        navigatorKey: _shellNavigatorKey,
        builder: (context, state, child) {
          return ScaffoldWithBottomNavBar(child: child);
        },
        routes: [
          // 商品列表路由
          GoRoute(
            path: '/products',
            name: AppRoute.products.name,
            redirect: (context, state) {
              print(state.toString());
              return null;
            },
            pageBuilder: (context, state) => NoTransitionPage(
              key: state.pageKey,
              restorationId: state.pageKey.value,
              child: const ProductsListScreen(),
            ),
            routes: [
              // 商品详情嵌套路由
              GoRoute(
                path: ':id',
                name: AppRoute.product.name,
                pageBuilder: (context, state) {
                  final productId = state.params['id']!;
                  // TODO: 实现Cupertino侧滑过渡
                  return MaterialPage(
                    key: state.pageKey,
                    restorationId: state.pageKey.value,
                    child: ProductScreen(productId: productId),
                  );
                },
              ),
            ],
          ),
          // 购物车路由
          GoRoute(
            path: '/cart',
            name: AppRoute.cart.name,
            pageBuilder: (context, state) => NoTransitionPage(
              key: state.pageKey,
              child: const ShoppingCartScreen(),
            ),
          ),
          // 账户页面路由
          GoRoute(
            path: '/account',
            name: AppRoute.account.name,
            pageBuilder: (context, state) => NoTransitionPage(
              key: state.pageKey,
              child: const AccountScreen(),
            ),
          ),
        ],
      ),
    ],
  );

ScaffoldWithBottomNavBar组件的build方法

@override
  Widget build(BuildContext context) {
    return Scaffold(
      body: widget.child,
      bottomNavigationBar: BottomNavigationBar(
        type: BottomNavigationBarType.fixed,
        unselectedItemColor: Colors.grey,
        selectedItemColor: Colors.black87,
        currentIndex: _selectedIndex,
        items: [
          BottomNavigationBarItem(
            icon: const Icon(
              Icons.list,
            ),
            label: '商品'.hardcoded,
          ),
          BottomNavigationBarItem(
            icon: const ShoppingCartIcon(),
            label: '购物车'.hardcoded,
          ),
          BottomNavigationBarItem(
            icon: const Icon(
              Icons.account_circle,
            ),
            label: '账户'.hardcoded,
          ),
        ],
        onTap: (index) => _tap(context, index),
      ),
    );
  }

标签按钮的回调逻辑

void _tap(BuildContext context, int index) {
    setState(() => _selectedIndex = index); // 用于更新标签高亮状态
    // 根据索引导航到对应路由
    if (index == 0) {
      context.goNamed(AppRoute.products.name);
    } else if (index == 1) {
      context.goNamed(AppRoute.cart.name);
    } else if (index == 2) {
      context.goNamed(AppRoute.account.name);
    }
  }

问题分析与尝试方案

我清楚当前实现无效的原因:直接让GoRouter导航到ShellRoute内的各个根路由。理想状态是切换标签页时,GoRouter能记住该标签页之前处于嵌套路由还是根路由状态。注意:和TabBar不同,BottomNavigationBar没有可用于切换索引的控制器。GoRouter 5.0版本较新,相关常见场景的文档和示例较少。

我曾尝试将选中的商品ID存储为应用状态,在/products路由的redirect函数中使用,但状态重置逻辑复杂,且NavigationObserver的尝试未达到预期效果。

更新说明

2023年6月28日更新
GoRouter 7.1.0版本新增了StatefulShellRoute类,专门支持这类标签页状态保留的场景。我撰写了完整教程讲解其用法:

  • Flutter底部导航栏结合GoRouter实现有状态嵌套路由

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 02:01:13