Skip to content

GoRouter 多参数传递指南

在 Flutter 中,当从传统的 Navigator 导航切换到 go_router 时,如何传递多个参数到其他页面是一个常见问题。本文将详细介绍在 go_router 中传递多个参数的几种最佳方法。

问题背景

在传统 Flutter 导航中,我们可以直接传递多个参数:

dart
Navigator.of(context).push(MaterialPageRoute(
  builder: (_) => CatalogFilterPage(
    list: list,
    bloc: bloc,
  )));

但在 go_router 中,我们需要使用不同的方法来处理参数传递。

版本兼容性注意

go_router 在不同版本中有重大变更:

  • 低于 7.0.0: 使用 paramsqueryParams
  • 7.0.0 到 10.0.0: 使用 pathParametersqueryParameters
  • 10.0.0 及以上: 使用 pathParametersuri.queryParameters

解决方案

1. 使用 pathParameters(路径参数)

当你知道参数的数量和名称时,可以使用路径参数。

定义路由

dart
GoRoute(
  path: '/sample/:id1/:id2',  // 在路径中定义参数
  name: 'sample',
  builder: (context, state) => SampleWidget(
    id1: state.pathParameters['id1'],
    id2: state.pathParameters['id2'],
  ),
),

导航到目标页面

dart
ElevatedButton(
  onPressed: () {
    var param1 = "param1";
    var param2 = "param2";
    context.goNamed("sample", pathParameters: {
      'id1': param1, 
      'id2': param2
    });
  },
  child: const Text("Navigate"),
),

接收参数

dart
class SampleWidget extends StatelessWidget {
  final String? id1;
  final String? id2;
  
  const SampleWidget({super.key, this.id1, this.id2});

  @override
  Widget build(BuildContext context) {
    // 使用参数...
  }
}

2. 使用 queryParameters(查询参数)

当参数数量不确定或需要传递可选参数时,使用查询参数。

定义路由

dart
GoRoute(
  name: "sample",
  path: "/sample",          
  builder: (context, state) => SampleWidget(
    id1: state.uri.queryParameters['id1'],
    id2: state.uri.queryParameters['id2'],
  ),
)

导航到目标页面

dart
ElevatedButton(
  onPressed: () {
    var param1 = "param1";
    var param2 = "param2";
    
    // 方法1: 使用 goNamed
    context.goNamed("sample", queryParameters: {
      'id1': param1, 
      'id2': param2
    });
    
    // 方法2: 使用 go 和 URL 参数
    // context.go("/sample?id1=$param1&id2=$param2");
  },
  child: const Text("Navigate"),
),

3. 使用 extra(传递对象)

当需要传递复杂对象时,可以使用 extra 参数。

定义路由

dart
GoRoute(
  path: '/item-screen',
  builder: (context, state) {
    MenuModels models = state.extra as MenuModels;
    return ItemScreen(menuModels: models);
  },
),

传递单个对象

dart
context.push(
  '/item-screen',
  extra: widget.menuModels,
);

传递多个对象

dart
context.goNamed(
  'path-name',
  extra: {
    'par1': object1,
    'par2': object2,
  },
);

// 在路由中接收
GoRoute(
  path: '/path',
  name: 'path-name',
  builder: (context, state) {
    Map<String, dynamic> extra = state.extra as Map<String, dynamic>;
    return ScreenName(
      par1: extra['par1'],
      par2: extra['par2'],
    );
  },
),

方法对比

选择正确的参数传递方式

方法适用场景优点缺点
pathParameters参数数量固定且已知类型安全,URL 清晰参数变化时需要修改路径
queryParameters参数可选或数量可变灵活,无需修改路径需要手动解析参数
extra传递复杂对象直接传递对象,无需序列化不支持深度链接

最佳实践

  1. 简单数据:使用 pathParametersqueryParameters
  2. 复杂对象:使用 extra 参数
  3. 保持一致性:在项目中统一参数传递方式
  4. 错误处理:总是对类型转换进行验证
dart
// 安全的类型转换示例
builder: (context, state) {
  final extra = state.extra;
  if (extra is Map<String, dynamic>) {
    return ScreenName(
      par1: extra['par1'] as YourType,
      par2: extra['par2'] as AnotherType,
    );
  } else {
    // 处理错误情况
    return ErrorWidget();
  }
},

总结

go_router 提供了多种传递参数的方法,每种方法都有其适用场景。根据你的具体需求选择合适的方法:

  • 使用 pathParameters 传递固定参数
  • 使用 queryParameters 传递可选参数
  • 使用 extra 传递复杂对象

正确使用这些方法可以让你的路由导航更加清晰和可维护。