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 选择,而是架构选择。

相关推荐
yingyima3 分钟前
Unix 时间戳转换实战:一次差点毁掉项目的低级错误
前端
IpdataCloud21 分钟前
IPv6时代,IP归属地查询服务精准度面临哪些挑战?实测对比+提升方案
运维·服务器·网络
盼兮29 分钟前
用AI编程从零搭建一个响应式数据看板
前端·人工智能·数据可视化
Lan.W30 分钟前
vue3-element-admin里新增mock接口一直没有生成,不生效
前端·javascript·vue.js·mock
小满zs31 分钟前
Next.js部署(Vercel)
前端·next.js
仙古.梦回~34 分钟前
vue-skills
前端·javascript·vue.js
倒霉熊dd1 小时前
Python 学习(第二部分:函数、模块与面向对象编程)
前端·数据库·python
上海云盾-小余1 小时前
服务器异常流量排查:攻击识别与快速限流处置指南
运维·服务器·网络
gCode Teacher 格码致知1 小时前
Javascrip提高:CSS backdrop-filter的使用方法-由Deepseek产生
前端·css
gCode Teacher 格码致知1 小时前
Javascript提高:canvas画布的网格背景-由Deepseek产生
javascript·css·css3