Flutter 路由从 Navigator 到 go_router:嵌套路由 / 登录守卫 / 深链一次讲透

这篇文章解决的核心问题(开宗明义)

Flutter 路由并不难,难的是:

  • 页面多了以后,怎么"管栈"

  • 登录态变化,怎么"统一跳转"

  • 深链 / 外部唤起,怎么"不写一堆 if else"

Dart 复制代码
Navigator.push(
  context,
  MaterialPageRoute(builder: (_) => DetailPage(id: 1)),
);

优点

  • 简单、直观

  • Demo / 小工具非常合适

问题(真实项目一定会遇到)

  • 页面跳转分散在各处

  • 登录判断写在 UI 里

  • 页面栈不可控(返回顺序混乱)

  • 深链几乎没法优雅接入

👉 本质问题

Navigator 1.0 是"命令式跳转",不是"路由系统"。

  • RouterDelegate

  • RouteInformationParser

  • 声明式页面栈

👉 方向是对的,但:

  • API 复杂

  • 维护成本高

  • 中小团队几乎不会手写

3️⃣ go_router:官方认可的"工程解法"

go_router 的定位一句话:

用"声明式路由 + 状态驱动跳转",解决真实 App 的路由问题

二、go_router 的核心设计思想(这段是你文章的"含金量")

1️⃣ 路由 = 状态映射,而不是 push 行为

Dart 复制代码
GoRoute(
  path: '/detail/:id',
  builder: (context, state) {
    final id = state.pathParameters['id'];
    return DetailPage(id: id);
  },
);

一句关键话:

UI 跳转不是"我要去哪",而是"当前状态对应哪个页面"。

2️⃣ 路由树 ≠ 页面树(这是很多人不懂的点)

Dart 复制代码
GoRoute(
  path: '/',
  builder: (_, __) => HomePage(),
  routes: [
    GoRoute(
      path: 'profile',
      builder: (_, __) => ProfilePage(),
    ),
  ],
);
  • /
  • /profile

👉 这是"嵌套路由",不是嵌套 Widget

三、嵌套路由:Tab / 子页面 / 页面栈治理

典型场景

  • BottomNavigation

  • 主页面 + 子功能页

  • 多模块 App

ShellRoute(一定要写)

Dart 复制代码
ShellRoute(
  builder: (context, state, child) {
    return Scaffold(
      body: child,
      bottomNavigationBar: BottomNav(),
    );
  },
  routes: [
    GoRoute(path: '/home', builder: ...),
    GoRoute(path: '/profile', builder: ...),
  ],
);

一个常见坑

❌ 不要用多个 Navigator 去硬拼

✅ 用 ShellRoute 统一管理"壳结构"

四、登录守卫(这部分你可以写得非常强)

1️⃣ 传统写法的问题

Dart 复制代码
onPressed: () {
  if (!loggedIn) {
    Navigator.push(LoginPage());
  }
}

❌ 登录逻辑散落

❌ 无法统一控制

❌ 深链直接绕过

2️⃣ go_router 的 redirect:登录态统一入口

Dart 复制代码
final router = GoRouter(
  redirect: (context, state) {
    final loggedIn = authRepo.isLogin;
    final loggingIn = state.location == '/login';

    if (!loggedIn && !loggingIn) return '/login';
    if (loggedIn && loggingIn) return '/';

    return null;
  },
);

💡 总结 (非常重要):

登录不是 UI 行为,而是"全局路由约束"。

五、深链(Deep Link):App 真正"像一个系统"的标志

1️⃣ 什么是深链

  • 外部 URL 直接打开某页面

  • 推送 / H5 / 浏览器唤起 App

2️⃣ go_router 天然支持

Dart 复制代码
GoRoute(
  path: '/product/:id',
  builder: (_, state) {
    final id = state.pathParameters['id']!;
    return ProductPage(id: id);
  },
);

系统唤起:

myapp://product/123

👉 不用手动解析,不用 if else

六、页面返回 & 参数回传

复制代码
final result = await context.push('/select');

context.pop(selectedValue);

📌 强调一句:

go_router 并没有"剥夺 Navigator 能力",只是统一了入口。

七、真实项目推荐路由结构(直接给模板)

Dart 复制代码
lib/
 ├─ router/
 │   ├─ app_router.dart
 │   ├─ auth_guard.dart
 │   └─ routes.dart
 ├─ pages/
 ├─ features/
Dart 复制代码
final router = GoRouter(
  routes: appRoutes,
  redirect: authRedirect,
);

👉 这是"团队可复制"的结构

八、Navigator vs go_router 对照总结

维度 Navigator go_router
跳转方式 命令式 声明式
登录控制 分散 集中
深链 困难 原生支持
页面栈 难管理 可预测
项目规模 中大型

一句收尾金句:

Flutter 项目一旦进入"多模块 + 登录态 + 深链"阶段,

路由不再是 API 选择,而是架构选择。

相关推荐
_F_y2 小时前
传输层协议:UDP
网络·网络协议·udp
掘金酱2 小时前
🏆2025 AI/Vibe Coding 对我的影响 | 年终技术征文
前端·人工智能·后端
成为大佬先秃头2 小时前
渐进式JavaScript框架:Vue
开发语言·javascript·vue.js
智算菩萨2 小时前
【Python基础】字典(Dictionary):AI的“键值对”信息存储的基石
前端·人工智能·python
沐森2 小时前
使用rust打开node的libuv实现多线程调用三种模式
javascript·rust
JiMoKuangXiangQu2 小时前
Linux 网络:RPS 简介
linux·网络·rps 和 rfs
C_心欲无痕2 小时前
vue3 - shallowReadonly浅层只读响应式对象
前端·javascript·vue.js
_Kayo_2 小时前
HTML 拖放API
前端·javascript·html
狗头大军之江苏分军2 小时前
2026年了,前端到底算不算“夕阳行业”?
前端·javascript·后端