前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用 GoRouter 进行 Flutter 导航:Go 与 Push

使用 GoRouter 进行 Flutter 导航:Go 与 Push

作者头像
徐建国
发布2022-06-24 14:11:59
2.4K0
发布2022-06-24 14:11:59
举报
文章被收录于专栏:个人路线

作者:坚果 华为云享专家,InfoQ签约作者,阿里云专家博主,51CTO博客专家,?开源项目GVA成员之一,OpenHarmony布道师,专注于大前端技术的分享,包括Flutter,小程序,安卓,VUE,JavaScript。

在使用 GoRouter 进行声明式路由时,深入解释 Go 和 Push 的区别

go_router 包是用于声明式路由的流行包。它基于 Navigator 2.0 API,目的是使用声明式路由来降低复杂性,无论您的目标平台是什么(移动、Web、桌面),处理来自 Android、iOS 和 Web 的深度和动态链接,以及其他一些导航相关的场景,同时(希望)提供易于使用的开发人员体验。当然所有这些都背后一个易于使用的 API。

如果您来自 Navigator 1.0,您将熟悉将路由送到导航堆栈的概念。

但是在使用 GoRouter 时,您有两个单独的选项:

  • go
  • push

本文将探讨两者的区别,以便您根据具体情况选择最合适的一种。

GoRouter 的声明式路由

首先,让我们考虑一个简单的路由层次结构,它由一个顶级路由和两个子路由组成:

代码语言:javascript
复制
GoRouter(
  initialLocation: '/',
  routes: [
    // top-level route
    GoRoute(
      path: '/',
      builder: (context, state) => const HomeScreen(),
      routes: [
        // one sub-route
        GoRoute(
          path: 'detail',
          builder: (context, state) => const DetailScreen(),
        ),
        // another sub-route
        GoRoute(
          path: 'modal',
          pageBuilder: (context, state) => const MaterialPage(
            fullscreenDialog: true,
            child: ModalScreen(),
          ),
        )
      ],
    ),
  ],
)

让我们为我们的路线定义 3 个页面:

主页、详细信息和model页面

从顶部路线导航

现在,假设我们在 HomeScreen中,这只是一个带有三个按钮的简单页面,回调定义如下:

代码语言:javascript
复制
// onPressed callback for the first button
context.go('/detail'),
// onPressed callback for the second button
context.push('/detail'),
// onPressed callback for the third button
context.go('/modal'),

第一个和第二个回调具有相同的目标位置( /detail),因此它们的行为方式相同。

也就是说,在这两种情况下,我们都会在导航堆栈中得到两条路线(home → detail)。

从首页到详情页

Go 和 Push 的区别

从详细信息页面,我们现在可以通过/modal两种不同的方式导航到:

代码语言:javascript
复制
// onPressed callback for the first button
context.go('/modal'),
// onPressed callback for the second button
context.push('/modal'),

**

这一次的结果不同:

  • 如果我们使用go,我们最终会在主页顶部显示模页面
  • 如果我们使用push,我们最终会在详细信息页面的顶部出现模态页面

Go 和 Push 如何影响导航堆栈

go 通过丢弃之前的路由(/detail)跳转到目标路由(/modal),因为 /modal 不是 /detail 的子路由:

img

具有 3 条路线的路线层次结构:请注意,modal 不是详细的子路线

同时,push总是将目标路由添加到现有路由之上,保留导航堆栈。


这意味着一旦我们关闭模态页面,我们将导航回:

  • 如果我们使用go,返回主页,
  • 如果我们使用push,返回详细信息页面

这是一个显示此行为的简短演示:

go vs push 路由:动画视频

最后附上完整源代码:

代码语言:javascript
复制
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  GoRouter.setUrlPathStrategy(UrlPathStrategy.path);
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final goRouter = GoRouter(
      debugLogDiagnostics: true,
      initialLocation: '/',
      routes: [
        GoRoute(
          path: '/',
          builder: (context, state) => const HomeScreen(),
          routes: [
            GoRoute(
              path: 'detail',
              builder: (context, state) => const DetailScreen(),
            ),
            GoRoute(
              path: 'modal',
              pageBuilder: (context, state) => const MaterialPage(
                fullscreenDialog: true,
                child: ModalScreen(),
              ),
            )
          ],
        ),
      ],
    );
    return MaterialApp.router(
      routerDelegate: goRouter.routerDelegate,
      routeInformationParser: goRouter.routeInformationParser,
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.amber,
      ),
    );
  }
}

class HomeScreen extends StatelessWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Home Page'),
        backgroundColor: Colors.red,
      ),
      backgroundColor: Colors.red,
      body: Padding(
        padding: const EdgeInsets.all(32.0),
        child: Center(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            mainAxisSize: MainAxisSize.min,
            children: [
              ElevatedButton(
                onPressed: () => context.go('/detail'),
                child: const CenteredText('go /detail'),
              ),
              const SizedBox(
                height: 32,
              ),
              ElevatedButton(
                onPressed: () => context.push('/detail'),
                child: const CenteredText('push /detail'),
              ),
              const SizedBox(
                height: 32,
              ),
              ElevatedButton(
                onPressed: () => context.go('/modal'),
                child: const CenteredText('go /modal'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class DetailScreen extends StatelessWidget {
  const DetailScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Detail Page'),
        backgroundColor: Colors.green,
      ),
      backgroundColor: Colors.green,
      body: Padding(
        padding: const EdgeInsets.all(32.0),
        child: Center(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            mainAxisSize: MainAxisSize.min,
            children: [
              ElevatedButton(
                onPressed: () => context.go('/modal'),
                child: const CenteredText('go /modal'),
              ),
              const SizedBox(
                height: 32,
              ),
              ElevatedButton(
                onPressed: () => context.push('/modal'),
                child: const CenteredText('push /modal'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class ModalScreen extends StatelessWidget {
  const ModalScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Modal Page'),
        backgroundColor: Colors.blue,
      ),
      backgroundColor: Colors.blue,
    );
  }
}

class CenteredText extends StatelessWidget {
  const CenteredText(this.text, {Key? key}) : super(key: key);
  final String text;
  @override
  Widget build(BuildContext context) {
    return Text(
      text,
      style: const TextStyle(fontSize: 30),
      textAlign: TextAlign.center,
    );
  }
}

结论

将 go 视为跳到新路线的一种方式。如果新路由不是旧路由的子路由,这将修改底层导航堆栈。

另一方面,push 将始终将目标路由推送到现有导航堆栈的顶部。


有关 GoRouter 的更多信息,请务必查看官方文档。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-04-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 大前端之旅 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • GoRouter 的声明式路由
  • 从顶部路线导航
  • Go 和 Push 的区别
  • 结论
相关产品与服务
云开发 CloudBase
云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档