flutter架 构项目基础

This commit is contained in:
崔宝新
2026-09-04 15:22:20 +08:00
parent 70967229d0
commit 0c5aee59c0
265 changed files with 35484 additions and 0 deletions
+104
View File
@@ -0,0 +1,104 @@
# 【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 这套入栈/出栈机制。