Skip to content

路由管理

概述

本文档详细介绍了 FluCli 项目模板中的路由管理方案,包括基于 Flutter 原生路由和 GetX 路由的两种实现方式。通过本文档,您将了解如何在 FluCli 项目中进行页面导航、参数传递和路由配置。

📋 路由方案对比

特性Flutter 原生路由GetX 路由
配置方式Map< String, WidgetBuilder >List< GetPage >
导航方法Navigator.pushNamed()Get.toNamed()
参数传递arguments 参数arguments + parameters
路由拦截需要自定义实现内置中间件支持
代码复杂度相对复杂简洁易用
性能原生性能轻微性能开销

🚀 Flutter 原生路由

js
class RouterS {
  /// 获取所有路由配置
  static Map<String, WidgetBuilder> getAllRoutS() {
    return {
      RouterIdConfig.demo: (context) => const DemoV(),
      RouterIdConfig.demoList: (context) => const DemoListV(),
      ...EgRouters.getRouters(),
    };
  }

  /// 设置默认入口页
  static configNoramlRouts() {
    return RouterIdConfig.demo;
  }
}

MaterialApp 配置

dart
Widget initMaterialApp({
  Widget Function(BuildContext, Widget?)? builder,
  required ThemeData theme,
}) {
  return MaterialApp(
    /// 全局导航键
    navigatorKey: NavigatorUtil.navigatorKey,
    
    /// 入口路由
    initialRoute: RouterS.configNoramlRouts(),
    
    /// 所有路由集合
    routes: RouterS.getAllRoutS(),
    
    /// 主题配置
    theme: theme,
    darkTheme: themeDataDark,
    
    /// 页面构建器
    builder: builder,
  );
}

页面导航

dart
// 基础导航
Navigator.pushNamed(context, '/demo');

// 带参数导航
Navigator.pushNamed(
  context, 
  '/demo',
  arguments: {'id': 123, 'title': '示例'}
);

// 替换当前页面
Navigator.pushReplacementNamed(context, '/home');

// 清除所有页面并导航
Navigator.pushNamedAndRemoveUntil(
  context,
  '/home',
  (route) => false,
);

参数获取

dart
class _DemoVState extends BaseStateV<DemoV> {
  @override
  void initState() {
    super.initState();
    
    // 获取路由参数
    final arguments = ModalRoute.of(context)?.settings.arguments;
    if (arguments != null && arguments is Map) {
      final id = arguments['id'];
      final title = arguments['title'];
      // 处理参数...
    }
  }
}

⚡ GetX 路由

路由配置

hzy_basic_project 项目中,使用 GetX 的路由管理方式:

dart
class RouterS {
  /// 获取所有路由配置
  static List<GetPage<dynamic>> getAllRoutS() {
    return [
      GetPage(
        name: RouterIdConfig.demo,
        page: () => DemoV(),
      ),
      GetPage(
        name: RouterIdConfig.demoList,
        page: () => DemoListV(),
      ),
      ...EgRouters.getRouters(),
    ];
  }

  /// 设置默认入口页
  static configNoramlRouts() {
    return RouterIdConfig.demo;
  }
}

GetMaterialApp 配置

dart
Widget initMaterialApp({
  Widget Function(BuildContext, Widget?)? builder,
}) {
  return GetMaterialApp(
    /// 入口路由
    initialRoute: RouterS.configNoramlRouts(),
    
    /// 所有路由集合
    getPages: RouterS.getAllRoutS(),
    
    /// 默认路由动画
    defaultTransition: Transition.rightToLeft,
    
    /// 主题配置
    theme: themeDataLight,
    darkTheme: themeDataDark,
    
    /// 路由监听
    navigatorObservers: [
      AppRouterObserver().routeObserver,
    ],
    
    builder: builder,
  );
}

GetX 导航工具

dart
/// 跳转到指定界面
currentToPage({
  required String name,
  Map<String, String>? parameters,
  dynamic arguments,
  Function(Map info)? onChange,
  bool preventDuplicates = true,
}) {
  return Get.toNamed(
    name,
    parameters: parameters,
    arguments: arguments,
    preventDuplicates: preventDuplicates,
  );
}

/// 底部弹出界面
bottomSheet({
  required Widget body,
  Color? barrierColor,
}) {
  Get.bottomSheet(
    body,
    barrierColor: barrierColor ?? Colors.black.withOpacity(0.6),
    exitBottomSheetDuration: const Duration(milliseconds: 300),
    enterBottomSheetDuration: const Duration(milliseconds: 300),
    isScrollControlled: true,
  );
}

/// 弹出对话框
dialog({required Widget body}) {
  Get.dialog(body);
}

GetX 页面导航

dart
// 基础导航
Get.toNamed('/demo');

// 带参数导航
Get.toNamed(
  '/demo',
  arguments: {'id': 123, 'title': '示例'},
  parameters: {'type': 'detail'}
);

// 替换当前页面
Get.offNamed('/home');

// 清除所有页面并导航
Get.offAllNamed('/home');

// 返回上一页
Get.back();

// 返回并传递结果
Get.back(result: {'success': true});

GetX 参数获取

dart
class DemoV extends BaseGetXV<DemoC> {
  @override
  DemoC get controller => Get.put(DemoC());
  
  @override
  void onInit() {
    super.onInit();
    
    // 获取 arguments 参数
    final arguments = Get.arguments;
    if (arguments != null && arguments is Map) {
      final id = arguments['id'];
      final title = arguments['title'];
    }
    
    // 获取 parameters 参数
    final type = Get.parameters['type'];
    
    // 处理参数...
  }
}

🔧 路由常用功能

路由拦截

GetX 路由拦截:

dart
GetPage(
  name: '/protected',
  page: () => ProtectedPage(),
  middlewares: [
    AuthMiddleware(), // 自定义中间件
  ],
);

class AuthMiddleware extends GetMiddleware {
  @override
  RouteSettings? redirect(String? route) {
    // 检查用户是否登录
    if (!UserService.isLoggedIn) {
      return const RouteSettings(name: '/login');
    }
    return null;
  }
}

原生路由拦截:

dart
class AppRouterDelegate extends RouterDelegate {
  @override
  Widget build(BuildContext context) {
    // 自定义路由逻辑
    if (!UserService.isLoggedIn) {
      return LoginPage();
    }
    return HomePage();
  }
}

路由动画

GetX 路由动画:

dart
GetPage(
  name: '/demo',
  page: () => DemoPage(),
  transition: Transition.fadeIn,
  transitionDuration: Duration(milliseconds: 300),
);

原生路由动画:

dart
Navigator.push(
  context,
  PageRouteBuilder(
    pageBuilder: (context, animation, secondaryAnimation) => DemoPage(),
    transitionsBuilder: (context, animation, secondaryAnimation, child) {
      return FadeTransition(opacity: animation, child: child);
    },
  ),
);

📝 最佳实践

1. 路由常量管理

dart
class RouterIdConfig {
  /// 主页
  static const String demo = "/demo";
  
  /// 列表页
  static const String demoList = "/demo_list";
  
  /// 详情页
  static const String detail = "/detail";
}

2. 统一导航工具

dart
class NavigationUtil {
  /// 跳转到详情页
  static void toDetail(String id) {
    // GetX 方式
    Get.toNamed('/detail', arguments: {'id': id});
    
    // 原生方式
    // Navigator.pushNamed(context, '/detail', arguments: {'id': id});
  }
  
  /// 返回首页
  static void toHome() {
    // GetX 方式
    Get.offAllNamed('/home');
    
    // 原生方式
    // Navigator.pushNamedAndRemoveUntil(context, '/home', (route) => false);
  }
}

3. 路由参数类型安全

dart
// 定义参数模型
class DetailPageArguments {
  final String id;
  final String title;
  
  DetailPageArguments({required this.id, required this.title});
}

// 使用类型安全的参数传递
NavigationUtil.toDetail(DetailPageArguments(
  id: '123',
  title: '示例标题',
));

🎯 选择建议

使用 Flutter 原生路由的场景:

  • 项目对性能要求极高
  • 团队更熟悉 Flutter 原生 API
  • 需要与现有原生路由系统集成
  • 项目规模较小,路由逻辑简单

使用 GetX 路由的场景:

  • 希望简化路由管理代码
  • 需要丰富的路由功能(中间件、动画等)
  • 项目已使用 GetX 状态管理
  • 快速开发和原型验证

📚 相关文档

根据 MIT 许可发布。