



这篇文章解决的核心问题(开宗明义)
Flutter 路由并不难,难的是:
页面多了以后,怎么"管栈"
登录态变化,怎么"统一跳转"
深链 / 外部唤起,怎么"不写一堆 if else"
一、为什么 Flutter 路由一定会"从 Navigator 走向 go_router"
1️⃣ Navigator 1.0:它不是不好,是管不了复杂 App
Dart
Navigator.push(
context,
MaterialPageRoute(builder: (_) => DetailPage(id: 1)),
);
优点
-
简单、直观
-
Demo / 小工具非常合适
问题(真实项目一定会遇到)
-
页面跳转分散在各处
-
登录判断写在 UI 里
-
页面栈不可控(返回顺序混乱)
-
深链几乎没法优雅接入
👉 本质问题:
Navigator 1.0 是"命令式跳转",不是"路由系统"。
2️⃣ Navigator 2.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 选择,而是架构选择。