Flutter:go_router如何将多个参数传递到其他屏幕?

36
在普通的Flutter中,我通常会像这样传递多个参数到其他屏幕:
    Navigator.of(context).push(MaterialPageRoute(
                                    builder: (_) => CatalogFilterPage(
                                          list: list,
                                          bloc: bloc,
                                        )))

相当简单和容易。我可以传递两个必需的参数,列表和 bloc。在 CatalogFilterPage 中使用它之后。
现在切换到 go_router 并查看 文档 后,似乎找不到如何传递多个数据。即使传递单个对象也不是很好:
    onTap: () =>
              context.pushNamed('SelectedCatalogItem', extra: list[index]),

在路由器中,我必须使用强制转换来设置正确的类型:

    builder: (context, state) => SelectedCatalogItem(
                    item: state.extra as ListItemsModel,
                  ),

对于单个参数来说还好,但现在我不知道如何传递多个参数。我该怎么做?甚至将模型等参数作为额外参数传递是否正确?

P.S. 我知道你可以通过context.pushNamed('CatalogFilterPage', params: ___)传递参数,但是params的类型是Map<String, String>,无法让我传递模型。


您可以参考此文档 - https://docs.flutter.dev/cookbook/navigation/navigate-with-arguments - Sparsh Jain
5个回答

131

编辑:Go_router 7.0.0 中的重大变更

enter image description here

简而言之
Below Go Router 7 i.e < 7.0.0 use `params`, `queryParams`
Above Go Router 7 i.e >=7.0.0 use `pathParameters`, `queryParameters`

摘要:

有三种方式:pathParametersqueryParametersextra

  1. 使用pathParameters
    • 当你事先知道参数的数量时
    • 用法:path = '/routeName/:id1/:id2'
  2. 使用queryParameters
    • 当你不确定参数的数量时
    • 用法:path = '/routeName'
  3. 使用extra
    • 当你想传递object

解释:

1. 使用 pathParameters

当您事先知道参数的数量时,请在 context.goNamed() 中使用 pathParameters 属性。

将其定义为:
GoRoute(
  path: '/sample/:id1/:id2',  //  Defination of params in the path is important
  name: 'sample',
  builder: (context, state) => SampleWidget(
    id1: state.pathParameters['id1'],
    id2: state.pathParameters['id2'],
  ),
),

称之为:
ElevatedButton(
  onPressed: () {
    var param1 = "param1";
    var param2 = "param2";
    context.goNamed("sample", pathParameters: {'id1': param1, 'id2': param2});
  },
  child: const Text("Hello"),
),
以以下方式接收:
class SampleWidget extends StatelessWidget {
  String? id1;
  String? id2;
  SampleWidget({super.key, this.id1, this.id2});

  @override
  Widget build(BuildContext context) {
     ...
  }
}

2. 使用 queryParameters

context.goNamed() 函数中,您可以访问到 queryParameters。关于 queryParameters 最好的一点是,您不需要在路由路径中显式定义它们,并且可以通过 state.queryParameters 方法轻松访问它们。您可以将各种与用户相关的数据添加为查询参数。

将其定义为:
GoRoute(
  name: "sample",
  path: "/sample",          
  builder: (context, state) => SampleWidget(
      id1: state.queryParameters['id1'],
      id2: state.queryParameters['id2'],
  ),
)
称之为:
ElevatedButton(
  onPressed: () {
    var param1 = "param1";
    var param2 = "param2";
    context.goNamed("sample", queryParameters: {'id1': param1, 'id2': param2});
  },
  child: const Text("Hello"),
),
以以下方式接收:
class SampleWidget extends StatelessWidget {
  String? id1;
  String? id2;
  SampleWidget({super.key, this.id1, this.id2});

  @override
  Widget build(BuildContext context) {
     ...
  }
}

3. 使用 extra

当你想在路由之间传递一个 model/object 时,请使用此功能。

GoRoute(
  path: '/sample',
  builder: (context, state) {
    Sample sample = state.extra as Sample; //  casting is important
    return GoToScreen(object: sample);
  },
),

参考https://dev59.com/EX0QtIcB2Jgan1znbFEa#74813017以了解在路由之间传递object的方法。

2
如果有人在State中访问extra对象时遇到问题,可以通过使用widget getter来解决,像这样:widget.object。 - makki
5
对于查询参数,GoRouterState不再直接从state中访问queryParameters。相反,请使用state.uri.queryParameters - undefined
请问如何传递多个对象? - undefined
@Faz 创建一个包含对象列表的模型,可以是数组或键值对,然后进行解析,类似于在 API 请求期间解析到和从模型中解析出来的方式。 - undefined
1
@krishnaacharyaa 非常感谢你!祝你有个愉快的一天! - undefined
显示剩余2条评论

8
我刚接触Flutter,这是我如何使用GoRouter的context.push()extra属性来传递多个参数/参数到路由的方法。
// navigate to /my-path, pass 2 arguments to context.state.extra
context.push("/my-path", extra: {"arg1": firstArg, "arg2": secondArg});

接着,在我的路由中:

// ...
// Use arguments in builder of the GoRoute
GoRoute(
  path: '/dashboard',
  builder: (context, state) {
    Map<String, MyCustomType> args =
      state.extra as Map<String, MyCustomType>;
    return MyWidget(arg1: args["arg1"]!, arg2: args["arg2"]!);
  }
),
// ...

5

这里是我的代码解决方案。在我的情况下,我想要从HomeScreen解析MenuModels到另一个屏幕(ItemScreen):

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

而在我的route.dart文件中

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

如果我们有多个额外的项怎么办?比如,假设ItemScreen既有菜单模型又有用户模型,那么我们该如何push呢? - alperefesahin
请使用 List<Object> 作为您的额外参数,并将其作为 extra: [object1, object2] 传递。 - Roslan Amir

3

go_router文档中,我们可以看到:

如果您想要简单地传递一个对象给构建器函数而无需通过URI传递对象标识符并从存储库中查找对象,则额外对象非常有用。

相反,您可以将“SelectedCatalogItem”的id/name作为params传入,并稍后形成这个对象(如果可能)。 “params”参数使我们能够传递多个字段。

onTap: () => context.pushNamed('SelectedCatalogItem',
                  params: {"id":list[index].id.toString(),"name":list[index].name}),

在GoRouter的构建器函数中,我们可以执行以下操作:
GoRoute(
        path: 'selectedCatalogItem/view/:id/:name',
        name: 'SelectedCatalogItem',
        builder: (context, state){
          int id = int.parse(state.params['id']!);
          String name = state.params['name']!;
          // use id and name to your use...
        });

嗨,当我使用你的代码时出现了一个错误:missing param "id" for /all/:name/:id。如何修复这个错误? - My Car

0

完成上面的示例(由@Agni Gari提供)

3. 使用额外的 context.goNamed()

当您想在路由之间传递模型/对象时,请使用此选项

将其定义为:

GoRoute(
    path: '/sample',
    name: 'sample',
    builder: (context, state) {
      Sample sample = state.extra as Sample; // -> casting is important
      return GoToScreen(object: sample);
    },
  ),

调用方式:

Sample sample = Sample(attributeA: "True",attributeB: "False",boolValue: false);
context.goNamed("sample",extra:sample );

将其接收为:

class SampleWidget extends StatelessWidget {
Sample? object;
SampleWidget({super.key, this.object});

  @override
  Widget build(BuildContext context) {
     ...
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接