简介
命名路由是一种通过字符串名称来标识和导航到页面的机制。它可以让路由管理更加清晰和集中。
基本配置
注册路由
MaterialApp(
// 注册路由表
routes: {
'/': (context) => HomePage(),
'/login': (context) => LoginPage(),
'/settings': (context) => SettingsPage(),
'/profile': (context) => ProfilePage(),
},
// 设置初始路由
initialRoute: '/',
// 处理未知路由
onUnknownRoute: (settings) {
return MaterialPageRoute(
builder: (context) => NotFoundPage(),
);
},
);
基本导航
// 导航到命名路由
Navigator.pushNamed(context, '/login');
// 替换当前路由
Navigator.pushReplacementNamed(context, '/home');
// 清空路由栈并导航
Navigator.pushNamedAndRemoveUntil(
context,
'/home',
(route) => false,
);
路由参数
传递参数
// 导航时传递参数
Navigator.pushNamed(
context,
'/detail',
arguments: {
'id': '123',
'title': 'Product Detail',
},
);
// 接收参数
class DetailPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final args = ModalRoute.of(context)!.settings.arguments as Map;
return Scaffold(
appBar: AppBar(
title: Text(args['title']),
),
body: Center(
child: Text('ID: ${args['id']}'),
),
);
}
}
完整示例
// 路由配置
class AppRoutes {
static const String home = '/';
static const String login = '/login';
static const String profile = '/profile';
static const String settings = '/settings';
static const String detail = '/detail';
static Map<String, WidgetBuilder> get routes => {
home: (context) => HomePage(),
login: (context) => LoginPage(),
profile: (context) => ProfilePage(),
settings: (context) => SettingsPage(),
detail: (context) => DetailPage(),
};
static Route<dynamic>? onUnknownRoute(RouteSettings settings) {
return MaterialPageRoute(
builder: (context) => NotFoundPage(),
);
}
}
// 主应用
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Named Routes Demo',
routes: AppRoutes.routes,
initialRoute: AppRoutes.home,
onUnknownRoute: AppRoutes.onUnknownRoute,
);
}
}
// 首页
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Home')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () => Navigator.pushNamed(
context,
AppRoutes.login,
),
child: Text('Go to Login'),
),
ElevatedButton(
onPressed: () => Navigator.pushNamed(
context,
AppRoutes.detail,
arguments: {
'id': '123',
'title': 'Product Detail',
},
),
child: Text('View Detail'),
),
],
),
),
);
}
}
// 详情页
class DetailPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final args = ModalRoute.of(context)!.settings.arguments as Map;
return Scaffold(
appBar: AppBar(
title: Text(args['title']),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('ID: ${args['id']}'),
ElevatedButton(
onPressed: () => Navigator.pop(context),
child: Text('Go Back'),
),
],
),
),
);
}
}
路由生成
onGenerateRoute
MaterialApp(
onGenerateRoute: (settings) {
if (settings.name == '/detail') {
final args = settings.arguments as Map;
return MaterialPageRoute(
builder: (context) => DetailPage(
id: args['id'],
title: args['title'],
),
);
}
return null;
},
);
最佳实践
- 路由名收敛到一个文件:
RouteNames类全 static const,跳转只写Get.toNamed(RouteNames.profile)——实战案例的教训:字符串散落各处,/idcard_verify写成/id_card_verify,按钮点了没反应查半天 - 路由表集中注册:
getPages: RoutePages.list,新增页面只改这一个地方;路由名用小写+下划线(/id_card_verify),别混驼峰 - 配 unknownRoute 兜底 404:拼错的路由名跳 404 页而不是白屏/没反应——把”我点的按钮没反应”变成”看得见的错误”
- 需要登录的页面挂 middleware:
GetPage(middlewares: [AuthMiddleware()])统一拦截,别在每个按钮 onPressed 里判登录(进阶篇实战:十几个入口漏了两个,被测试抓包)
注意事项
- 路由名全局唯一:
/detail在两个 GetPage 里各注册一次,后注册的覆盖先注册的,跳过去的页面不对还很难查 - 带参命名路由用 Get.parameters 取参:
/detail?id=123的 123 用 parameters 取,路由名本身保持干净的/detail,别把参数拼进路由名字符串 - 命名路由和直接传 widget 定一种为主:团队约定好(作者:需深链接/统一管理的走命名,临时弹页走
Get.to(() => Page()))——混用可以,但要有规则 - 改路由名用 IDE 重构:static const 的好处就是改名能全局重构;直接改字符串漏一处就是线上 bug
实战案例
命名路由我最大的体会是:路由名一定要收敛到一个文件。在 某物流冷链项目 里我建了 RouteNames 类:static const main = '/'、static const idCardVerify = '/id_card_verify'、static const driverVerify = '/driver_verify' 等十几个,全是 static const。然后 GetMaterialApp(getPages: RoutePages.list) 集中注册。跳转时写 Get.toNamed(RouteNames.profile),IDE 能跳转、改名能重构。反面教材是我早期项目里直接写字符串 '/profile',有一次把 /idcard_verify 写成 /id_card_verify,跑起来点按钮没反应,查了半天。所以命名路由的重点根本不是”怎么命名”,而是”怎么不让字符串散落各处”。
总结
命名路由提供了一种更加结构化的页面导航方式。通过合理使用命名路由,可以让应用的导航逻辑更加清晰和易于维护。
