写点什么

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

作者:坚果
  • 2022 年 4 月 28 日
  • 本文字数:3453 字

    阅读完需:约 11 分钟

作者:坚果

公众号:"大前端之旅"

华为云享专家,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 的声明式路由

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


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中,这只是一个带有三个按钮的简单页面,回调定义如下:


// onPressed callback for the first buttoncontext.go('/detail'),// onPressed callback for the second buttoncontext.push('/detail'),// onPressed callback for the third buttoncontext.go('/modal'),
复制代码


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


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


Go 和 Push 的区别

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


// onPressed callback for the first buttoncontext.go('/modal'),// onPressed callback for the second buttoncontext.push('/modal'),
复制代码



**


这一次的结果不同:


  • 如果我们使用go,我们最终会在主页顶部显示模页面

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



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



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


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




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


  • 如果我们使用go,返回主页,

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


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



最后附上完整源代码:


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 月 28 日阅读数: 21
用户头像

坚果

关注

此间若无火炬,我便是唯一的光 2020.10.25 加入

公众号:“大前端之旅”,华为云享专家,InfoQ签约作者,51CTO博客首席体验官,专注于大前端技术的分享,包括Flutter,小程序,安卓,VUE,JavaScript。

评论

发布
暂无评论
使用 GoRouter 进行 Flutter 导航:Go 与 Push_4月月更_坚果_InfoQ写作社区