Appearance
Flutter 路由:go_router / Navigator 体系
Flutter 路由的核心不是浏览器 URL,而是 内存中的页面栈 + 声明式/命令式导航策略。
代码索引
| 主题 | Lab 说明 | 源码 |
|---|---|---|
| Navigator.pushNamed / pop(result) 基础路由 | flutter-routing-basic | routing_home_page.dart · routing_detail_page.dart |
| go_router 声明式路由 / redirect / path+query 参数 | flutter-routing-go-router | go_router_demo.dart |
为什么需要
Flutter 项目里,路由问题很容易从“小功能”演变成“全局复杂度”:
- 页面怎么跳
- 参数怎么传
- 返回值怎么回
- 深链怎么接
- 登录态拦截放哪
- URL 同步与页面栈如何统一
如果只会 Navigator.push,到稍大一点的工程就会混乱。
底层机制
1. Navigator 本质是页面栈
Flutter 默认导航模型更接近:
text
push -> 入栈
pop -> 出栈所以:
- 打开详情页,首页通常还在栈里
- 返回时不是“重新创建整个 App”,而是回到上一层栈页面
- 页面返回值可以直接通过
pop(result)传回
2. 命令式 vs 声明式
命令式(Navigator 1.x 风格)
典型写法:
dart
Navigator.of(context).pushNamed('/detail');
Navigator.of(context).pop(result);特点:
- 上手快
- 适合小型 demo 与简单业务流
- 页面栈行为直观
声明式(Router / go_router)
典型思路:
- 路由状态是“当前配置”
- 页面树由路由状态推导
- 更适合深链、重定向、嵌套路由、Web URL 同步
3. 参数与返回值是两条链路
- 进入详情页:arguments / path / query 传入
- 返回上一页:
Navigator.pop(result)回传
这两条链路不要混为一种“全靠全局状态”。
Android / Flutter / Web / Backend 对照
| 维度 | Flutter | Android | Web | Backend |
|---|---|---|---|---|
| 进入详情页 | Navigator.push/pushNamed | startActivity / NavController | router.push | 请求进入子资源接口 |
| 返回上一页 | pop() | finish() / back stack | 浏览器 back | 请求结束,无页面栈 |
| 传参 | arguments / path / query | Intent extras / nav args | path / query | request params |
| 回传结果 | pop(result) | Activity Result API | 常靠全局状态或 URL | response body |
| 栈管理 | 内存页面栈 | Activity / Fragment back stack | 浏览器历史栈 | 无 UI 栈 |
常见场景
1. 订单页跳详情,再回传操作结果
例如:
- 首页打开订单详情
- 详情页完成取消/确认动作
- 返回首页后刷新指定条目
这时非常适合用 pop(result),而不是一开始就上全局事件总线。
对应 Lab:flutter-routing-basic · routing_home_page.dart · routing_detail_page.dart · flutter-routing-go-router · go_router_demo.dart
2. 登录态拦截
- 小项目里容易散在每个按钮点击前判断
- 稍大一些的项目应统一收敛到路由层(尤其 go_router redirect)
3. Web / H5 / App 对齐
如果项目有 WebView / H5 / Flutter 混合场景,就要提前想清:
- 页面路径谁是事实源
- query/path 参数怎么映射
- 返回行为是否统一
常见坑
| 坑 | 现象 | 修法 |
|---|---|---|
把所有导航都写成匿名 MaterialPageRoute | 路由分散、难做统一治理 | 集中 onGenerateRoute 或路由配置中心 |
| 参数全靠全局变量 | 页面复用差、测试困难 | 明确使用 arguments / path / query |
| 页面返回后靠猜测刷新 | 首页状态不稳定 | 使用 await push... + pop(result) |
| 一上来全项目硬上最复杂 go_router 嵌套路由 | 理解成本高、改动重 | 先把页面栈与参数/返回值模型吃透 |
与相近概念对比
| 概念 | 适合场景 | 优点 | 风险 |
|---|---|---|---|
Navigator.push | 小功能、一次性跳转 | 简单直接 | 路由散落 |
pushNamed | 统一收敛命名路由 | 中心化管理更好 | 命名与参数约束要维护 |
go_router | 深链、redirect、嵌套路由 | 适合中大型工程 | 学习与配置成本更高 |
| 全局状态驱动导航 | 跨模块事件流 | 某些复杂流程可用 | 容易隐式、难排查 |
对应实验
各章节内已嵌入跳转链接;此处汇总全部 Lab:
| Lab | 说明 | 源码 |
|---|---|---|
| flutter-routing-basic | flutter-routing-basic | routing_home_page.dart · routing_detail_page.dart |
| flutter-routing-go-router | flutter-routing-go-router | go_router_demo.dart |
复习检查题
Flutter 默认导航模型为什么更像“页面栈”而不是“浏览器 URL”?
答:因为默认
Navigator维护的是内存中的 route stack,push入栈、pop出栈;页面返回更多是栈回退,而不是浏览器地址栏驱动。为什么详情页结果回传优先考虑
pop(result)?答:因为它天然贴合页面栈语义,调用方可
await得到结果,避免把简单回传问题上升成全局状态或事件总线。go_router相比基础Navigator更适合什么场景?答:更适合深链、登录态重定向、嵌套路由、Web URL 同步、多层路由治理等中大型工程场景。
速记
Navigator:页面栈pushNamed:统一入口pop(result):直接回传- 小场景先吃透栈模型
- 大场景再上
go_router