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

3.5 KiB
Raw Blame History

【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 拿到值。


二、怎么运行 / 演示内容

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,取值需判空强转。',
)

五、踩坑记录

  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(Navigator.pop(context, '男'));
  • 参数接收的两种通道见 detail_page.md;
  • 真实项目推荐 go_router:声明式路由 + 守卫 + 深链,但底层仍是 Navigator 这套入栈/出栈机制。