flutter开发实战-GoRouter路由go与push区别实践

news2024/11/25 22:27:05

flutter开发实战-GoRouter路由go与push区别实践

GoRouter是一个flutter的声明性路由包,使用路由器API提供一个方便的、基于url的API,用于在不同屏幕之间导航。可以定义URL模式、使用URL导航、处理深度链接以及许多其他与导航相关的场景。

之前使用了GoRouter,介绍了GoRouter相关使用细节。这里来测试一下GoRouter路由go与push区别。

在Flutter Web项目中,usePathUrlStrategy是一个用于设置URL策略的方法。默认情况下,Flutter Web使用的是Hash(#)URL,这意味着路由信息会被包含在URL的#后面,这样对SEO不是很友好。

如果你希望使用Path URL Strategy,即example.com/path而不是example.com/#/path,你可以在main函数中调用usePathUrlStrategy()。

一、使用页面跳转

配置路由home->detail->comment

final GoRouter _router = GoRouter(
  routes: <RouteBase>[
    GoRoute(
      path: '/',
      builder: (BuildContext context, GoRouterState state) {
        return const HomeScreen();
      },
      routes: <RouteBase>[
        GoRoute(
          path: 'details',
          builder: (BuildContext context, GoRouterState state) {
            return const DetailsScreen();
          },
        ),
        GoRoute(
          path: 'comment/:id',
          builder: (BuildContext context, GoRouterState state) {
            String? id = state.pathParameters['id'];
            print("id:${id}"); // Get "id" param from URL
            return CommentScreen(id: id);
          },
        )
      ],
    ),
  ],
);
    
  • 在使用GoRouterHelper的go方法进行路由跳转的情况。

home->details

ElevatedButton(
              onPressed: () => context.go('/details'),
              child: const Text('Go to the Details screen'),
            ),
    

details->comment

ElevatedButton(
              onPressed: () => context.go('/comment/55555'),
              child: const Text('Go to the comment screen'),
            ),
    

使用go跳转效果如下
在这里插入图片描述

  • 在使用GoRouterHelper的push方法进行路由跳转的情况。

home->details

ElevatedButton(
              onPressed: () => context.push('/details'),
              child: const Text('Go to the Details screen'),
            ),
    

details->comment

ElevatedButton(
              onPressed: () => context.push('/comment/55555'),
              child: const Text('Go to the comment screen'),
            ),
    

使用push跳转效果如下

在这里插入图片描述

二、go与push区别

通过以上测试,我们可以看到区别,如图

在这里插入图片描述

在这里插入图片描述
GoRouter中的go与push区别

go:使用Go时候,会在主页顶部显示模态页面
push:使用情况,会在上一级页面显示模态页面

在使用Go,go通过丢弃之前的路由(/detail)跳转到目标路由(/comment),因为(/comment)不是(/detail)的路由
在使用push,push总是将目标路由添加到现有路由之上,保留导航堆栈。

例如 A->B->C->D页面跳转逻辑
如果使用go的情况下
A->B->C->D,从C或者D页面返回pop的情况下,会直接返回到A页面
如果使用push的情况下
A->B->C->D,从D页面返回会回到C页面,C页面返回会回到B页面,B页面返回会回到A页面。

在flutter的web项目跳转的时候的区别
在使用Go情况下,setUrlStrategy(PathUrlStrategy());设置后,浏览器会显示跳转的路径如http://localhost:55478/details
在使用push的情况下,setUrlStrategy(PathUrlStrategy());设置后,浏览器不会显示。没有遵循PathUrlStrategy的path url策略

查看源码GoRoute源码可以看出

/// 当我们查看GoRoute源码时候,会发现一个GoRouteInformationProvider类,实现系统RouteInformationProvider类的方法:routerReportsNewRouteInformation
/// push:Pushes the location as a new route on top of base.
/// push 将location推入页面stack的顶部
///
/// go:Replace the current route matches with the location.
/// go 将location替换当前路线
///
/// 可以查看NavigatingType可以看到相应的区别

enum NavigatingType {
/// Push new location on top of the [RouteInformationState.baseRouteMatchList].
push,
///
/// Push new location and remove top-most [RouteMatch] of the
/// [RouteInformationState.baseRouteMatchList].
pushReplacement,
///
/// Push new location and replace top-most [RouteMatch] of the
/// [RouteInformationState.baseRouteMatchList].
replace,
///
/// Replace the entire [RouteMatchList] with the new location.
go,
/// }

GoRouter是实现系统API类RouteInformationProvider与SystemNavigator使用,
在routerReportsNewRouteInformation中调用SystemNavigator的selectMultiEntryHistory();与SystemNavigator.routeInformationUpdated方法。

完整代码如下

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:flutter_web_plugins/url_strategy.dart';


void main() {
  WidgetsFlutterBinding.ensureInitialized();
  setUrlStrategy(PathUrlStrategy());
  runApp(const MyApp());
}

class MyNavigatorObserver extends NavigatorObserver {
  @override
  void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
    print('did push route');
  }

  @override
  void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {
    print('did pop route');
  }
}

final GoRouter _router = GoRouter(
  observers: [MyNavigatorObserver()],
  redirect: (BuildContext context, GoRouterState state) {
    final isLogin = true; // your logic to check if user is authenticated
    if (!isLogin) {
      return '/login';
    } else {
      return null; // return "null" to display the intended route without redirecting
    }
  },
  errorBuilder: (
      BuildContext context,
      GoRouterState state,
      ) {
    // ErrorPage
    return ErrorScreen();
  },
  routes: <RouteBase>[
    GoRoute(
      path: '/',
      builder: (BuildContext context, GoRouterState state) {
        return const HomeScreen();
      },
      routes: <RouteBase>[
        GoRoute(
          path: 'details',
          builder: (BuildContext context, GoRouterState state) {
            return const DetailsScreen();
          },
          routes: <RouteBase>[
            // Add child routes
            GoRoute(
              path: 'sub-details',
              // NOTE: Don't need to specify "/" character for router’s parents
              builder: (context, state) {
                return SubDetailsScreen();
              },
              pageBuilder: (context, state) {
                return CustomTransitionPage(
                  child: SubDetailsScreen(),
                  transitionsBuilder: (BuildContext context,
                      Animation<double> animation,
                      Animation<double> secondaryAnimation,
                      Widget child) {
                    return FadeTransition(
                      opacity:
                      Tween(begin: 0.1, end: 1.0).animate(CurvedAnimation(
                        parent: animation,
                        curve: Curves.fastOutSlowIn,
                      )),
                      child: child,
                    );
                  },
                );
              },
            ),
          ],
        ),
        GoRoute(
          path: 'comment/:id',
          builder: (BuildContext context, GoRouterState state) {
            String? id = state.pathParameters['id'];
            print("id:${id}"); // Get "id" param from URL
            return CommentScreen(id: id);
          },
        ),
        GoRoute(
          path: 'search',
          // builder: (BuildContext context, GoRouterState state) {
          //   String? keyword = state.queryParameters['keyword'];
          //   print("keyword:${keyword}"); // Get "id" param from URL
          //   return SearchScreen(keyword: keyword);
          // },
          pageBuilder: (context, state) {
            String? keyword = state.queryParameters['keyword'];
            print("keyword:${keyword}"); // Get "id" param from URL
            return CustomTransitionPage(
              child: SearchScreen(keyword: keyword),
              transitionsBuilder: (BuildContext context,
                  Animation<double> animation,
                  Animation<double> secondaryAnimation,
                  Widget child) {
                return FadeTransition(
                  opacity:
                  Tween(begin: 0.1, end: 1.0).animate(CurvedAnimation(
                    parent: animation,
                    curve: Curves.fastOutSlowIn,
                  )),
                  child: child,
                );
              },
            );
          },
        ),
      ],
    ),
  ],
);

/// The main app.
class MyApp extends StatelessWidget {
  /// Constructs a [MyApp]
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerConfig: _router,
    );
  }
}

/// The home screen
class HomeScreen extends StatelessWidget {
  /// Constructs a [HomeScreen]
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Home Screen')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: () => context.go('/details'),
              child: const Text('Go to the Details screen'),
            ),
            SizedBox(
              height: 30,
            ),
            ElevatedButton(
              onPressed: () => context.go('/details/sub-details'),
              child: const Text('Go to the SubDetails screen'),
            ),
          ],
        ),
      ),
    );
  }
}

/// The details screen
class DetailsScreen extends StatelessWidget {
  /// Constructs a [DetailsScreen]
  const DetailsScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Details Screen')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: () => context.push('/comment/55555'),
              child: const Text('Go to the comment screen'),
            ),
            SizedBox(
              height: 30,
            ),
            ElevatedButton(
              onPressed: () => context.push('/search?keyword=myName'),
              child: const Text('Go to the Search screen'),
            ),
          ],
        ),
      ),
    );
  }
}

/// The details screen
class SubDetailsScreen extends StatelessWidget {
  /// Constructs a [SubDetailsScreen]
  const SubDetailsScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('SubDetailsScreen Screen')),
      body: Center(
        child: ElevatedButton(
          onPressed: () => context.push('/details'),
          child: const Text('Go back to the Details screen'),
        ),
      ),
    );
  }
}

/// The details screen
class CommentScreen extends StatelessWidget {
  /// Constructs a [DetailsScreen]
  const CommentScreen({super.key, this.id});

  final String? id;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('CommentScreen Screen')),
      body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              Text("param id:${id}"),
              SizedBox(
                height: 30,
              ),
              ElevatedButton(
                onPressed: () => context.pop(),
                child: const Text('Go back to the Details screen'),
              ),
            ],
          )),
    );
  }
}

/// The Search screen
class SearchScreen extends StatelessWidget {
  /// Constructs a [DetailsScreen]
  const SearchScreen({super.key, this.keyword});

  final String? keyword;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('SearchScreen Screen')),
      body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              Text("param keyword:${keyword}"),
              SizedBox(
                height: 30,
              ),
              ElevatedButton(
                onPressed: () => context.push('/'),
                child: const Text('Go back to the details screen'),
              ),
            ],
          )),
    );
  }
}

/// The Search screen
class ErrorScreen extends StatelessWidget {
  /// Constructs a [DetailsScreen]
  const ErrorScreen();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('ErrorScreen Screen')),
      body: Center(
        child: Container(
          child: const Text('Error info'),
        ),
      ),
    );
  }
}

    

三、小结

flutter开发实战-GoRouter路由go与push区别实践

学习记录,每天不停进步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2123492.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue3封装table表格右键菜单功能

1) 效果&#xff0c;右键单击单元格&#xff0c;打开菜单弹窗: 点击菜单选项&#xff0c;可选择只读/编辑&#xff0c;可在只读/编辑方法中&#xff0c;拿到该行列表格的数据&#xff0c;进行相关操作 2) 思路 1、右键菜单组件 出现的时机&#xff0c;是右键单击table表格row-…

移动安全需求分析与安全保护工程

移动应用安全威胁与需求分析 移动应用系统组成&#xff1a; 移动应用&#xff1a;简称App 通信网络&#xff1a;无线网络&#xff0c;移动通信网络及互联网 应用服务端&#xff1a;由相关服务器构成&#xff0c;负责处理来自App相关信息或数据 移动应用安全分析 Android系统…

【0基础】制作HTML网页小游戏——贪吃蛇(附详细解析)

我在昨天的文章&#xff08;贪吃蛇HTML源码&#xff09;里面分享了网页版贪吃蛇小游戏的源码&#xff0c;今天就来给大家详细讲解一下每部分代码是如何运作的&#xff0c;以及以后要如何美化贪吃蛇的UI界面&#xff0c;在哪里修改等。 目录 一、代码运作 1、HTML结构: 2、C…

数组的常用算法

数组是同类型数据的集合。便于整体处理数据&#xff0c;数组操作的主要算法有&#xff1a; 1求极值 2查找 3排序 2查找 cprimer plus第11.1节278--279页 4数组和指针的区别&#xff1a;数组表示法和指针表示法 数组表示法1 int a[4]{2,4,1,5}; for(int i0;i<4;i)cou…

JAVA 的excel数据批量导入解析 现在都用什么API工具 Apache POI 、EasyExcel 、easypoi有什么区别

&#x1f4dd;个人主页&#x1f339;&#xff1a;个人主页 ⏩收录专栏⏪&#xff1a;SpringBoot &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339;&#xff0c;让我们共同进步&#xff01; 在Java中&#xff0c;处理Excel数据批量导入解析时&#xff0c;常…

通讯录

在写一个程序前需要了解的知识&#xff0c;需要对通讯录的流程了如指掌&#xff0c;才能写出一个完整的程序 。 写一个主函数&#xff0c;里面包含菜单、对菜单的选择、以及循环。创建个人信息结构体&#xff0c;多人构成的结构体数组。分析每一个函数&#xff1a; 1).增加信…

webstorm修改主题色和配色常用插件(全部实用)包含主题、界面、开发效率等

Windows 用户打开setting 选择配色 更换主题看这里 效率插件 Rainbow Brackets 推荐理由&#xff1a;用各种鲜明的颜色显示括号&#xff0c;这样可以很容易分清楚括号配对问题。 Key promoter 推荐理由&#xff1a;只要是鼠标操作能够用快捷键替代的&#xff0c;Key Promoter…

若依漏洞综合利用工具

若依漏洞综合利用工具 安装与使用 该工具使用java开发&#xff0c;环境要求&#xff1a;JDK1.8版本 java -jar “文件名” 即可打开图形化界面。 注意查看"必看操作说明"模块。 1.首先下载好几个必要模块。 然后把openjfx-17.0.11_windows-x64_bin-sdk放在D盘根…

音视频入门基础:AAC专题(1)——AAC官方文档下载

一、AAC简介 高级音频编码&#xff08;英语&#xff1a;Advanced Audio Coding&#xff0c;AAC&#xff09;是有损音频压缩的专利数字音频编码标准&#xff0c;由Fraunhofer IIS、杜比实验室、贝尔实验室、Sony、Nokia等公司共同开发。出现于1997年&#xff0c;为一种基于MPEG…

【python因果推断库14】饮酒年龄 - 贝叶斯分析

目录 饮酒年龄 - 贝叶斯分析 主效应模型 交互模型 将连续变量以治疗阈值为中心 饮酒年龄 - 贝叶斯分析 这个例子使用了回归断点设计来探讨最低合法饮酒年龄&#xff08;在美国为21岁&#xff09;对全因死亡率的因果效应。数据集来自carpenter2009effect 的一项研究。 impo…

C语言蓝桥杯:语言基础

竞赛常用库函数 最值查询 min_element和max_element在vector(迭代器的使用) nth_element函数的使用 例题lanqiao OJ 497成绩分析 第一种用min_element和max_element函数的写法 第二种用min和max的写法 二分查找 二分查找只能对数组操作 binary_search函数&#xff0c;用于查找…

yolov8实现图片验证码识别

1、环境准备 1.1、安装miniconda 地址&#xff1a;Index of /anaconda/miniconda/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 注意&#xff1a;为避免不兼容的问题&#xff0c;推荐下载py38版本&#xff0c;我下载的是Miniconda3-py38_23.1.0-1-Windows-x86_…

【Java 类与对象】多态

空山新雨后 天气晚来秋 目录 多态的概念 多态实现条件 多态的转型 向上转型 向下转型 instanceof 关键字 方法的重写 Override注解 重写的权限 只能重写继承而来的方法&#xff08;1&#xff09; final、static 不能被重写&#xff08;2&#xff09; 重写的方法不能带有等级更严…

向量——通俗地解释

1. 向量 向量是一个既有大小(模)又有方向的对象&#xff0c;它可以用来描述空间中的位置、力或速度等量。我们可以从物理、数学和计算机的角度来看待向量&#xff0c;这三种观点看似不同却有关联。 &#xff08;1&#xff09;在物理专业视角下&#xff0c;向量是空间中的箭头&a…

KubeBlocks 如何降低管理多种数据库的学习门槛

什么是 KubeBlocks KubeBlocks 是一个开源的 Kubernetes 数据库 operator&#xff0c;能够帮助用户在 Kubernetes 上运行和管理多种类型的数据库。据我们所知&#xff0c;大多数数据库 operator 通常只能管理某种特定类型的数据库&#xff0c;例如&#xff1a; CloudNativePG…

秋招突击——算法练习——9/4——73-矩阵置零、54-螺旋矩阵、48-旋转图像、240-搜索二维矩阵II

文章目录 引言复习新作73-矩阵置零个人实现 54-螺旋矩阵个人实现参考实现 48-旋转图像个人实现参考实现 240-搜索二维矩阵II个人实现参考实现 总结 引言 秋招开展的不是很顺利&#xff0c;还是要继续准备&#xff0c;继续刷算法&#xff01;不断完善自己&#xff0c;希望能够找…

Jupyter notebook配置与使用(安装过程+环境配置+运行实例)

前言 Jupyter Notebook 是一个开放源代码的 Web 应用程序&#xff0c;它允许创建和共享包含实时代码、方程式、可视化和叙述性文本的文档。 主要功能&#xff1a; 交互式计算&#xff1a;用户可以直接在浏览器中编写和执行代码。Markdown 支持&#xff1a;使用 Markdown 格式来…

一道迭代器失效练习题

随便写写 首先学习迭代器失效 传送门 : C—浅谈迭代器失效 学完迭代器失效之后做一道题呗 题目 分析 vector的迭代器为啥会失效 1、插入的时候扩容&#xff0c;转移空间出现野指针 2、删除的时候移动了元素&#xff0c;导致指针没指向正确的元素 list的迭代器为啥会失效 li…

pdf怎么压缩?分享5种压缩PDF文件的方法

pdf怎么压缩&#xff1f;PDF文件的压缩在日常办公和学习中尤为重要&#xff0c;它不仅能够大幅度缩减文件大小&#xff0c;节省宝贵的存储空间&#xff0c;还能加快文件在网络中的传输速度&#xff0c;提升工作效率。特别是在处理包含大量图像或复杂布局的PDF文档时&#xff0c…

Http带消息头两种请求办法

API接口最近经常碰到&#xff0c;协调几个乙方来回对接&#xff0c;把我折腾晕了&#xff0c;索性自己写一个小的工具&#xff0c;导入历史数据。 获取平台免登录token 接口说明 URL Path&#xff1a;gateweb/bigm-dm/openApi/ologin/openLogin 说明&#xff1a;第三方免登…