# 【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 ? 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` 传对象,原理一致。