Files
App.K12.Student.Miniapp_Flu…/docs/demos/router_home_page.md
T
2026-09-04 15:22:20 +08:00

105 lines
3.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 【Demo】路由首页:三种跳转姿势
> 源文件:`lib/pages/demo/router_home_page.dart` | 分类:路由
> 一句话:push 传参 / await 接返回值 / pushNamed 命名路由 —— 跳转的三个基本姿势。
---
## 一、这个 Demo 解决什么问题
页面跳转是 App 的基本操作。本页演示三种姿势及其适用场景:
1. **push + 构造函数传参**:参数少、类型安全,最常用;
2. **push 并等待返回结果**:从"选择器页"带值回来(选性别等);
3. **pushNamed 命名路由 + arguments**:按路由名跳转,参数以 Map 传递。
> 核心思想:**页面跳转是"入栈/出栈"**(Navigator 是个栈)。
> push = 压栈,pop = 出栈;pop 时带值 → push 的 await 拿到值。
---
## 二、怎么运行 / 演示内容
```dart
runApp(const RouterApp());
```
- 方式 1:跳详情页(张三,18);
- 方式 2:跳选择器页,选"男/女" → 返回首页弹 SnackBar 显示选择结果;
- 方式 3:跳详情页(李四,25,走命名路由)。
---
## 三、核心知识点(新手向)
### 1. 方式 1:push + 构造函数传参(类型安全,首选)
```dart
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => const DetailPage(name: '张三', age: 18),
),
);
```
- 参数是 Dart 强类型:写错类型编译期就报错;
- 页面构造写在 `builder` 里(路由是"惰性构建",进入页面才执行)。
### 2. 方式 2:await push 接收 pop 返回值
```dart
onPressed: () async {
// 注意:push 返回的是 Future,用 await 接收 pop 带回来的值
final result = await Navigator.push<String>(
context,
MaterialPageRoute(builder: (_) => const PickerPage()),
);
if (context.mounted) { // await 之后必须判 mounted!
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('你选择了:${result ?? '未选择'}')),
);
}
},
```
- 泛型 `<String>` 声明返回类型;
- 用户点系统返回键(没有 pop 带值)→ result 为 null,`?? '未选择'` 兜底;
- **await 后 context.mounted 必须判**(页面可能已被销毁)。
### 3. 方式 3:pushNamed 命名路由 + arguments
```dart
Navigator.pushNamed(
context,
'/detail', // 必须在 MaterialApp.routes 里注册过
arguments: {'name': '李四', 'age': 25},
);
```
- arguments 是 `dynamic`(任意类型),取值需判空强转(见 [detail_page.md](detail_page.md));
- 适合路由名集中管理的场景,代价是**丢失了类型安全**。
---
## 四、关键代码剖析
```dart
// 页面底部常驻的知识点提示(学习型 Demo 的惯例)
Text(
'知识点:页面跳转是【入栈/出栈】。'
'返回页 pop 时带值 → 接收页 await push 拿到值。'
'命名路由的 arguments 是 dynamic,取值需判空强转。',
)
```
---
## 五、踩坑记录
1. **`await` 之后用 `context` 必须先判 `context.mounted`**(Flutter 3.7+ 的推荐写法,替代旧式 `if (!mounted) return`);
2. `pushNamed` 没在 routes 注册 → 运行期 `onUnknownRoute` 报错/黑屏;
3. 忘了 `await push` 就收不到 pop 返回值;
4. 返回结果用泛型约束:`Navigator.push<String>`,别让类型随意流转。
---
## 六、扩展思考
- pop 带值的一方见 [picker_page.md](picker_page.md)(`Navigator.pop(context, '男')`);
- 参数接收的两种通道见 [detail_page.md](detail_page.md);
- 真实项目推荐 go_router:声明式路由 + 守卫 + 深链,但底层仍是 Navigator 这套入栈/出栈机制。