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