如果你正在用 Flutter,却依然被“路由”折磨到想跑路——这篇就是为你写的。
页面跳转写半天、传参像走钢丝、Web 端刷新一下直接 404……
别担心,你不是一个人。
今天,我们就把 Navigator 1.0、Navigator 2.0、GoRouter 的迷雾全部吹散。一次性打通 Flutter 路由任督二脉,从此页面跳转不再头疼!
🤯 为什么 Flutter 路由让人抓狂?
因为 Flutter 路由历史上发生过“三次进化”,导致网上教程新旧混杂,坑多到埋不完:
●Navigator 1.0 —— 简单粗暴,但功能弱鸡
●Navigator 2.0 —— 功能无敌,但复杂到劝退 99% 的人
●GoRouter —— 终于出现一个“人类可用”的官方方案
但现在的问题是:新手不知道用哪个?老项目不敢升级?Web 端 Link 更是压力山大?
这篇文章帮你彻底解决“到底选谁”的终极疑问。
❤️ Navigator 1.0:你入门 Flutter 的初恋
适合场景: 小项目、个人 Demo、纯粹的新手学习
这是大家最熟悉的代码:
●●● Dart// 基础使用 - 简单到哭
Navigator.push(
context,
MaterialPageRoute(builder: (context) => DetailsPage()),
);
// 命名路由 - 稍微优雅点
MaterialApp(
routes: {
'/': (context) => HomePage(),
'/details': (context) => DetailsPage(),
},
);
// 跳转时
Navigator.pushNamed(context, '/details');
✅ 优点:
●符合直觉,栈的操作(Push/Pop)。
●3分钟就能学会。
❌ 致命缺点:
●深层链接(Deep Link)无能为力: 你没法通过 URL 直接打开 App 的特定页面。
●Web 端体验极差: 浏览器的地址栏不会变,刷新一下直接回到首页,用户心态崩了。
●嵌套路由困难: 想做复杂的后台管理系统?难如登天。
🧠 Navigator 2.0:真正的强者,但学习门槛极高
为什么会出现 2.0?因为 Google 想让 Flutter 完美支持 Web。 你需要 URL 同步、浏览器前进后退、多 Tab 独立导航栈... 1.0 架构根本做不到。
于是 2.0 来了,但它的 API 设计极其抽象:
●●● Dart// 2.0的典型用法 - 确实复杂一些
MaterialApp.router(
routeInformationParser: MyRouteInformationParser(),
routerDelegate: MyRouterDelegate(),
);
// 但理解后会发现其强大之处
class MyRouterDelegate extends RouterDelegate<String>
with PopNavigatorRouterDelegateMixin<String>, ChangeNotifier {
final List<String> _pages = ['/home'];
@override
Widget build(BuildContext context) {
returnNavigator(
key: navigatorKey,
pages: _pages.map((route) =>
MaterialPage(
key: Key(route),
child: _generatePage(route),
)).toList(),
onPopPage: (route, result) {
if (!route.didPop(result)) returnfalse;
_pages.removeLast();
notifyListeners();
returntrue;
},
);
}
}
你需要手动管理路由栈的状态,代码量是 1.0 的十倍以上。
结论: 除非你是架构师,或者有极致的定制需求,否则千万别直接用原生的 Navigator 2.0,那是给自己找罪受。
🌟 GoRouter:Flutter 官方给全世界的礼物
Google 自己也发现 Navigator 2.0 太难用了,于是推出了 GoRouter。 它底层封装了 Navigator 2.0 的强大能力,表层却提供了极其简单的 API。
它就是目前 90% 项目的最优解。
1. 声明路由简单到哭
●●● Dart// 配置简单到令人发指
final GoRouter router = GoRouter(
routes: [
GoRoute(
path: '/',
builder: (context, state) => constHomeScreen(),
),
GoRoute(
path: '/details/:id',
builder: (context, state) {
final String id = state.pathParameters['id']!;
returnDetailsScreen(id: id);
},
),
],
);
2. 跳转极其优雅
●●● Dart// 不需要 MaterialPageRoute,也不需要 Context 传递 Widget
// 跳转简单直观
context.go('/details/123'); // 替换当前栈
context.push('/details/123'); // 推入新页面
3.嵌套路由?So easy!
●●● Dart// 底部导航栏轻松实现
StatefulShellRoute.indexedStack(
builder: (context, state, navigationShell) {
returnScaffoldWithNavBar(navigationShell: navigationShell);
},
branches: [
// 首页分支
StatefulShellBranch(routes: [
GoRoute(path: '/home', builder: (context, state) => HomeScreen()),
]),
// 个人中心分支
StatefulShellBranch(routes: [
GoRoute(path: '/profile', builder: (context, state) => ProfileScreen()),
]),
],
)
🔥 真正的干货:GoRouter 实战必杀技
很多教程只讲基础,下面这两个功能才是 GoRouter 真正的“大杀器”。
⚔️ 杀手锏 1:一行代码搞定“底部导航保活”
这是新手最容易踩的坑:切换底部 Tab 时,页面被销毁了,滚动位置丢了! 以前你可能要用 PageStorage 或者 AutomaticKeepAliveClientMixin 折腾半天。
在 GoRouter 中,使用 StatefulShellRoute,直接起飞:
●●● Dart// 伪代码示例
StatefulShellRoute.indexedStack(
builder: (context, state, navigationShell) {
// 这里返回你的 Scaffold + BottomNavigationBar
returnMainScreen(navigationShell: navigationShell);
},
branches: [
// Tab 1: 首页
StatefulShellBranch(
routes: [GoRoute(path: '/home', builder: (c, s) => HomePage())],
),
// Tab 2: 个人中心
StatefulShellBranch(
routes: [GoRoute(path: '/user', builder: (c, s) => UserPage())],
),
],
)
效果: 无论你怎么切换 Tab,页面状态完美保留,不需要写一行 KeepAlive 代码!
⚔️ 杀手锏 2:Web 端参数传递的“死亡陷阱”
❌ 错误写法(新手必踩): 很多同学喜欢用 extra 传对象:
●●● Dart// 跳转时传了一个 User 对象
context.go('/profile', extra: userObject);
💥 后果: 在 App 端没问题。但在 Web 端,用户按一下 F5 刷新,或者把链接分享给朋友打开。 extra 会变成 null,页面直接红屏报错! 因为对象不能存在 URL 字符串里。
✅ 正确写法: 永远通过 URL Path 或 Query Parameters 传递 ID,然后在页面内根据 ID 重新拉取数据。
●●● Dart// 推荐:将 ID 放在 URL 里
context.go('/profile/${user.id}');
// 目标页面拿到 ID 后,用 Riverpod/Bloc 去读缓存或请求网络
🎯 总结:到底应该怎么选?
别纠结了,我给你最实用的选择逻辑:
✅ 90% 的项目 → 直接锁死 GoRouter
●适用: 商业 App、电商、工具、社交、需要 Web 版、需要 Deep Link。
●理由: 官方维护,生态最好,功能最全,团队协作成本最低。
🟡 纯新手 / 只有2-3个页面的 Demo → Navigator 1.0
●适用: 学习 Dart 语言、写个计算器 Demo。
●理由: 别让路由配置消磨了你入门的热情。
🔥 巨型复杂应用 / 框架开发者 → Navigator 2.0
●适用: 你需要自己写一个路由框架,或者你的 App 导航逻辑反人类。
●理由: 只有它能提供原子级的控制力。
从今天开始,新项目请无脑选择 GoRouter。
它已经成为了 Flutter 开发的事实标准。哪怕你现在只开发 App,未来某天老板突然说:“我们要支持 Web 端分享”,用了 GoRouter 的你只需要微微一笑:“好的,已经支持了。”
这就是架构选型的远见。
🎤 你们项目现在的路由架构是什么?
🎤 有没有遇到过 “安卓返回键退出了 App 却没返回上一页” 的抓狂瞬间?
(觉得有用,记得点赞 分享 收藏,让更多 Flutter 兄弟不再踩坑!)
🎤 欢迎在评论区吐苦水!