87 lines
2.7 KiB
Markdown
87 lines
2.7 KiB
Markdown
# 【Demo】详情页:参数接收的两种通道
|
||
|
||
> 源文件:`lib/pages/demo/detail_page.dart` | 分类:路由
|
||
> 一句话:构造参数与 ModalRoute arguments 双通道 —— 谁来了用谁,缺谁兜底。
|
||
|
||
---
|
||
|
||
## 一、这个 Demo 解决什么问题
|
||
|
||
同一个详情页,可能被两种方式打开:
|
||
- **方式 1**:`push` 构造传参(`DetailPage(name: '张三', age: 18)`);
|
||
- **方式 3**:`pushNamed` 命名路由 + arguments(`{'name': '李四', 'age': 25}`)。
|
||
|
||
页面要**同时兼容两种入口**:优先用 arguments 里的值,没有就用构造参数兜底。
|
||
|
||
---
|
||
|
||
## 二、怎么运行 / 演示内容
|
||
|
||
```dart
|
||
runApp(const RouterApp());
|
||
```
|
||
首页分别用方式 1 / 方式 3 跳进来,观察两种取参路径的效果。
|
||
|
||
---
|
||
|
||
## 三、核心知识点(新手向)
|
||
|
||
### 1. 构造参数(类型安全)
|
||
```dart
|
||
class DetailPage extends StatelessWidget {
|
||
const DetailPage({super.key, this.name = '默认', this.age = 0});
|
||
|
||
final String name;
|
||
final int age;
|
||
...
|
||
}
|
||
```
|
||
- 带默认值 → 不传参也能打开,不会崩;
|
||
- 类型安全:传错类型编译期报错。
|
||
|
||
### 2. 命名路由 arguments(运行期 Map)
|
||
```dart
|
||
final args = ModalRoute.of(context)?.settings.arguments;
|
||
final argMap = args is Map<String, dynamic> ? args : null;
|
||
```
|
||
- `ModalRoute.of(context)` 拿到当前路由 → `.settings.arguments` 取出 pushNamed 传的参数;
|
||
- arguments 是 dynamic,**必须判空强转**:
|
||
- 不是 Map(或没传)→ `argMap` 为 null;
|
||
- `argMap?['name']` 取不到时用 `?? name` 回退构造参数。
|
||
|
||
### 3. 双通道合并取值(本页精髓)
|
||
```dart
|
||
Text('姓名:${argMap?['name'] ?? name}'),
|
||
Text('年龄:${argMap?['age'] ?? age}'),
|
||
```
|
||
"arguments 优先,构造参数兜底"——两种入口都兼容,缺参不崩。
|
||
|
||
---
|
||
|
||
## 四、关键代码剖析
|
||
|
||
```dart
|
||
// 手动 pop(AppBar 的返回箭头也是 pop,效果一样)
|
||
OutlinedButton(
|
||
onPressed: () => Navigator.pop(context),
|
||
child: const Text('返回上一页'),
|
||
)
|
||
```
|
||
|
||
---
|
||
|
||
## 五、踩坑记录
|
||
|
||
1. `arguments` 是 dynamic,**直接用会崩**(`args['name']` 对非 Map 类型运行期报错)——先 `is Map` 判断;
|
||
2. `ModalRoute.of(context)?.settings.arguments` 有 `?`,路由可能为 null;
|
||
3. 构造参数给默认值,保证"零参数也能打开页面"(debug 直达页面时很有用);
|
||
4. 命名路由注册在 [router_demo.md](router_demo.md) 的 routes 表里。
|
||
|
||
---
|
||
|
||
## 六、扩展思考
|
||
|
||
- 选择器页 pop 带值见 [picker_page.md](picker_page.md);
|
||
- 参数多了建议封装成强类型对象(`class DetailArgs`),避免 Map 满天飞;
|
||
- 真实项目(go_router)用 `GoRoute` 的 `arguments` 或 `extra` 传对象,原理一致。
|