Flutter中路由配置的各种方案

我来为你详细介绍Flutter中路由配置的各种方案,包括它们的特色、优缺点和实际代码示例。

1. 基础路由(MaterialApp.routes)

特色

  • Flutter最基础的路由配置方式
  • 适合简单的应用场景
  • 配置简单直观

优缺点

优点 :简单易用,学习成本低 缺点:功能有限,不支持复杂路由场景

实际代码

dart 复制代码
// main.dart
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '基础路由示例',
      initialRoute: '/',
      routes: {
        '/': (context) => HomePage(),
        '/details': (context) => DetailsPage(),
      },
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('首页')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            // 导航到详情页
            Navigator.pushNamed(context, '/details');
          },
          child: Text('前往详情页'),
        ),
      ),
    );
  }
}

class DetailsPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('详情页')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: Text('返回'),
        ),
      ),
    );
  }
}

传参方式

基础路由不支持直接传参,需要通过ModalRoute获取参数:

dart 复制代码
// 传参
Navigator.pushNamed(context, '/details', arguments: {
  'id': 123,
  'title': '示例标题'
});

// 获取参数
class DetailsPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final args = ModalRoute.of(context)!.settings.arguments as Map<String, dynamic>;
    final id = args['id'];
    final title = args['title'];
    
    return Scaffold(
      appBar: AppBar(title: Text(title)),
      body: Center(
        child: Text('ID: $id'),
      ),
    );
  }
}

2. onGenerateRoute(动态路由)

特色

  • 支持动态路由生成
  • 可以处理复杂的路由逻辑
  • 支持参数验证和转换

优缺点

优点 :灵活性强,支持复杂路由逻辑 缺点:配置相对复杂

实际代码

dart 复制代码
// main.dart
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '动态路由示例',
      initialRoute: '/',
      onGenerateRoute: (RouteSettings settings) {
        switch (settings.name) {
          case '/':
            return MaterialPageRoute(builder: (context) => HomePage());
          case '/details':
            final args = settings.arguments as Map<String, dynamic>?;
            return MaterialPageRoute(
              builder: (context) => DetailsPage(
                id: args?['id'] ?? 0,
                title: args?['title'] ?? '默认标题',
              ),
            );
          case '/profile':
            final userId = settings.arguments as String?;
            return MaterialPageRoute(
              builder: (context) => ProfilePage(userId: userId ?? 'unknown'),
            );
          default:
            return MaterialPageRoute(
              builder: (context) => NotFoundPage(routeName: settings.name ?? ''),
            );
        }
      },
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('首页')),
      body: Center(
        child: Column(
          children: [
            ElevatedButton(
              onPressed: () {
                Navigator.pushNamed(context, '/details', arguments: {
                  'id': 123,
                  'title': '动态路由示例'
                });
              },
              child: Text('前往详情页'),
            ),
            ElevatedButton(
              onPressed: () {
                Navigator.pushNamed(context, '/profile', arguments: 'user123');
              },
              child: Text('前往个人主页'),
            ),
          ],
        ),
      ),
    );
  }
}

class DetailsPage extends StatelessWidget {
  final int id;
  final String title;

  const DetailsPage({required this.id, required this.title});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(title)),
      body: Center(
        child: Column(
          children: [
            Text('ID: $id'),
            Text('标题: $title'),
          ],
        ),
      ),
    );
  }
}

class ProfilePage extends StatelessWidget {
  final String userId;

  const ProfilePage({required this.userId});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('个人主页')),
      body: Center(
        child: Text('用户ID: $userId'),
      ),
    );
  }
}

class NotFoundPage extends StatelessWidget {
  final String routeName;

  const NotFoundPage({required this.routeName});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('页面未找到')),
      body: Center(
        child: Text('路由 "$routeName" 不存在'),
      ),
    );
  }
}

3. 命名路由(Named Routes)

特色

  • 使用字符串标识路由
  • 支持路由堆栈管理
  • 适合中大型应用

优缺点

优点 :路由管理清晰,支持pushNamed、popUntil等操作 缺点:参数传递需要额外处理

实际代码

dart 复制代码
// routes.dart
class AppRoutes {
  static const String home = '/';
  static const String details = '/details';
  static const String profile = '/profile';
  static const String settings = '/settings';
}

// main.dart
import 'package:flutter/material.dart';
import 'routes.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '命名路由示例',
      initialRoute: AppRoutes.home,
      routes: {
        AppRoutes.home: (context) => HomePage(),
        AppRoutes.details: (context) => DetailsPage(),
        AppRoutes.profile: (context) => ProfilePage(),
        AppRoutes.settings: (context) => SettingsPage(),
      },
      onGenerateRoute: (settings) {
        // 处理未定义的路由
        if (settings.name == '/unknown') {
          return MaterialPageRoute(
            builder: (context) => NotFoundPage(),
          );
        }
        return null;
      },
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('首页')),
      body: Center(
        child: Column(
          children: [
            ElevatedButton(
              onPressed: () {
                // 普通跳转
                Navigator.pushNamed(context, AppRoutes.details);
              },
              child: Text('前往详情页'),
            ),
            ElevatedButton(
              onPressed: () {
                // 替换当前路由
                Navigator.pushReplacementNamed(context, AppRoutes.profile);
              },
              child: Text('替换到个人主页'),
            ),
            ElevatedButton(
              onPressed: () {
                // 跳转并清除所有路由
                Navigator.pushNamedAndRemoveUntil(
                  context,
                  AppRoutes.settings,
                  (route) => false,
                );
              },
              child: Text('跳转到设置页(清除堆栈)'),
            ),
          ],
        ),
      ),
    );
  }
}

class DetailsPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('详情页')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: Text('返回'),
        ),
      ),
    );
  }
}

class ProfilePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('个人主页')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: Text('返回'),
        ),
      ),
    );
  }
}

class SettingsPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('设置页')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: Text('返回'),
        ),
      ),
    );
  }
}

class NotFoundPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('页面未找到')),
      body: Center(
        child: Text('页面不存在'),
      ),
    );
  }
}

4. 第三方路由库(go_router)

特色

  • 声明式路由管理
  • 支持深度链接
  • 强大的路由守卫

优缺点

优点 :功能强大,支持复杂路由场景 缺点:需要学习第三方库

实际代码

首先添加依赖:

yaml 复制代码
# pubspec.yaml
dependencies:
  go_router: ^14.0.0
dart 复制代码
// main.dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  final GoRouter _router = GoRouter(
    routes: [
      GoRoute(
        path: '/',
        builder: (context, state) => HomePage(),
        routes: [
          GoRoute(
            path: 'details/:id',
            builder: (context, state) {
              final id = state.pathParameters['id']!;
              final title = state.uri.queryParameters['title'] ?? '默认标题';
              return DetailsPage(id: int.parse(id), title: title);
            },
          ),
          GoRoute(
            path: 'profile',
            builder: (context, state) => ProfilePage(),
          ),
        ],
      ),
    ],
    errorBuilder: (context, state) => NotFoundPage(),
  );

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      title: 'GoRouter示例',
      routerConfig: _router,
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('首页')),
      body: Center(
        child: Column(
          children: [
            ElevatedButton(
              onPressed: () {
                // 路径参数 + 查询参数
                context.go('/details/123?title=GoRouter示例');
              },
              child: Text('前往详情页'),
            ),
            ElevatedButton(
              onPressed: () {
                // 相对路径
                context.go('/profile');
              },
              child: Text('前往个人主页'),
            ),
            ElevatedButton(
              onPressed: () {
                // 传递额外参数
                context.go('/details/456', extra: {'from': 'home'});
              },
              child: Text('带额外参数跳转'),
            ),
          ],
        ),
      ),
    );
  }
}

class DetailsPage extends StatelessWidget {
  final int id;
  final String title;

  const DetailsPage({required this.id, required this.title});

  @override
  Widget build(BuildContext context) {
    final extra = GoRouterState.of(context).extra as Map<String, dynamic>?;
    
    return Scaffold(
      appBar: AppBar(title: Text(title)),
      body: Center(
        child: Column(
          children: [
            Text('ID: $id'),
            Text('标题: $title'),
            if (extra != null) Text('来源: ${extra['from']}'),
            ElevatedButton(
              onPressed: () {
                context.pop();
              },
              child: Text('返回'),
            ),
          ],
        ),
      ),
    );
  }
}

class ProfilePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('个人主页')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            context.pop();
          },
          child: Text('返回'),
        ),
      ),
    );
  }
}

class NotFoundPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('页面未找到')),
      body: Center(
        child: Text('页面不存在'),
      ),
    );
  }
}

5. 自定义路由管理器

特色

  • 完全自定义控制
  • 适合特殊需求
  • 高度灵活

优缺点

优点 :完全控制路由逻辑 缺点:开发成本高

实际代码

dart 复制代码
// custom_router.dart
import 'package:flutter/material.dart';

class CustomRouteManager {
  static final CustomRouteManager _instance = CustomRouteManager._internal();
  factory CustomRouteManager() => _instance;
  CustomRouteManager._internal();

  final Map<String, WidgetBuilder> _routes = {};
  final Map<String, Route<dynamic> Function(RouteSettings)> _routeFactories = {};

  void registerRoute(String path, WidgetBuilder builder) {
    _routes[path] = builder;
  }

  void registerRouteFactory(String path, 
      Route<dynamic> Function(RouteSettings) factory) {
    _routeFactories[path] = factory;
  }

  Route<dynamic>? generateRoute(RouteSettings settings) {
    // 优先使用路由工厂
    if (_routeFactories.containsKey(settings.name)) {
      return _routeFactories[settings.name]!(settings);
    }
    
    // 使用普通路由
    if (_routes.containsKey(settings.name)) {
      return MaterialPageRoute(
        builder: _routes[settings.name]!,
        settings: settings,
      );
    }
    
    return null;
  }

  void navigateTo(BuildContext context, String path, 
      {Map<String, dynamic>? arguments}) {
    Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => _buildPage(path, arguments),
      ),
    );
  }

  Widget _buildPage(String path, Map<String, dynamic>? arguments) {
    if (_routes.containsKey(path)) {
      return _routes[path]!(BuildContext(null));
    }
    return NotFoundPage(routeName: path);
  }
}

// main.dart
import 'package:flutter/material.dart';
import 'custom_router.dart';

void main() {
  // 注册路由
  final router = CustomRouteManager();
  router.registerRoute('/', (context) => HomePage());
  router.registerRoute('/details', (context) => DetailsPage());
  
  runApp(MyApp(router: router));
}

class MyApp extends StatelessWidget {
  final CustomRouteManager router;

  const MyApp({required this.router});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '自定义路由示例',
      home: HomePage(),
      onGenerateRoute: router.generateRoute,
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('首页')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            CustomRouteManager().navigateTo(context, '/details', 
              arguments: {'id': 123, 'title': '自定义路由'});
          },
          child: Text('前往详情页'),
        ),
      ),
    );
  }
}

class DetailsPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('详情页')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: Text('返回'),
        ),
      ),
    );
  }
}

class NotFoundPage extends StatelessWidget {
  final String routeName;

  const NotFoundPage({required this.routeName});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('页面未找到')),
      body: Center(
        child: Text('路由 "$routeName" 不存在'),
      ),
    );
  }
}

总结对比

方案 适用场景 优点 缺点
基础路由 简单应用 简单易用 功能有限
动态路由 中等复杂度 灵活性强 配置复杂
命名路由 中大型应用 管理清晰 参数处理麻烦
go_router 复杂应用 功能强大 学习成本高
自定义路由 特殊需求 完全控制 开发成本高

参数传递方式总结

  1. 路径参数/user/123state.pathParameters['id']
  2. 查询参数/user?id=123state.uri.queryParameters['id']
  3. 额外参数arguments属性 → ModalRoute.of(context)!.settings.arguments
  4. 构造函数传参:最推荐的方式,类型安全

选择哪种方案取决于你的应用复杂度、团队熟悉度和具体需求。对于大多数应用,推荐使用onGenerateRoutego_router

相关推荐
不一样的少年_4 小时前
女朋友炸了:刚打开的网页怎么又没了?我反手甩出一键恢复按钮!
前端·javascript·浏览器
Renounce4 小时前
【Android】让 Android 界面 “动” 起来:动画知识点大起底
前端
Asort4 小时前
JavaScript设计模式(十四)——命令模式:解耦请求发送者与接收者
前端·javascript·设计模式
小茴香3534 小时前
Vue 脚手架(Vue CLI)
前端·javascript·vue.js
午安~婉4 小时前
ESLint
前端·eslint·检查
“抚琴”的人4 小时前
C#中获取程序执行时间
服务器·前端·c#
掘金一周4 小时前
Flex 布局下文字省略不生效?原因其实很简单| 掘金一周 10.16
前端
Stringzhua4 小时前
Vue的Axios介绍【9】
前端·javascript·vue.js
摸着石头过河的石头4 小时前
JavaScript 垃圾收集:内存管理的艺术
前端·javascript