Flutter中封装Fluro路由配置,以及无context跳转与传参

fluro路由简单配置

  • 引入fluro

pubspec.yaml

yml 复制代码
dependencies:
	# 路由管理
  fluro: ^2.0.5

一、封装fluro路由

  • 主要初始化路由表信息,以及找不到页面时默认返回404页面

lib/router/routes.dart

dart 复制代码
import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
import 'package:planx_app/pages/home/router/router_test_page.dart';
import 'package:planx_app/pages/index_page.dart';
import 'package:planx_app/widget/empty.dart';

class Routes {
  static FluroRouter router = FluroRouter();
  // 设置页面
  // 页面信息
  static String indexPage = "/";
  // 路由测试页面
  static String routerPage = "/routerTest";

  // 初始化,配置路由表
  static _initRouter() {
    // 首页
    router.define(indexPage,
        handler: Handler(handlerFunc: (_, __) => const IndexPage()));
    // 路由测试页面
    router.define(routerPage,
        handler: Handler(handlerFunc: (_, __) => const RouterTestPage()));
  }

  // 配置路由
  static void configureRoutes() {
    router.notFoundHandler = Handler(handlerFunc: (_, __) {
      // 找不到路由时,返回404页面
      return Scaffold(
          appBar: AppBar(),
          // 这是自行封装的Empty组件
          body: const Center(child: Empty(type: EmptyType.page404)));
    });
    // 初始化路由信息
    _initRouter();
  }
}

main.dart 中初始化与配置路由

dart 复制代码
import 'package:planx_app/router/routes.dart';

void main() async {
	// ...
  // 注册路由
  Routes.configureRoutes();
  runApp(const MyApp());
}
// ....
// MaterialApp中配置路由
MaterialApp(
  // ...
  // 配置路由
  onGenerateRoute: Routes.router.generator,
);

二、封装页面跳转的方法

  • flutter中可以直接使用Navigator进行路由调整,为了统一建议还是先封装一下
  • 这里只是简单的封装,在后面还有介绍关于无context跳转,以及特殊参数传递的封装

lib/router/navigator_util.dart

dart 复制代码
import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
import 'package:planx_app/router/routes.dart';

class NavigatorUtil {
  static void push(
    BuildContext context,
    String path, {
    bool replace = false, // 替换当前页面
    bool clearStack = false,  // 是否清空路由栈
    Object? arguments,
    TransitionType? transition,  // 页面进入动效
  }) {
    Routes.router.navigateTo(
      context,
      path,
      replace: replace,
      clearStack: clearStack,
      // 页面进入从右侧进入
      transition: transition ?? TransitionType.inFromRight,
      // routeSettings需要在对应页面接收:ModalRoute.of(context)?.settings.arguments;
      routeSettings: RouteSettings(
        arguments: arguments,
      ),
    );
  }
}

使用

dart 复制代码
 ElevatedButton(
  onPressed: () {
    NavigatorUtil.push(context, Routes.routerPage);
  },
  child: const Text("跳转路由测试页面"),
),

效果:

无context跳转

有些时候我们可能不会在builder中跳转路由,所以没有context

  • 在MaterialApp中有一个navigatorKey属性,指定navigatorKey后就可以直接操作Navigator,不需要使用context

重新封装路由跳转方法

lib/router/navigator_util.dart

dart 复制代码
import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
import 'package:planx_app/router/routes.dart';

// 全局key,用于无context跳转的情况
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();

class NavigatorUtil {
  // 无context跳转
  static void push(
    String path, {
    bool replace = false,
    bool clearStack = false,
    Object? arguments,
    TransitionType? transition,
  }) {
    Routes.router.navigateTo(
      navigatorKey.currentContext!,
      path,
      replace: replace,
      clearStack: clearStack,
      transition: transition ?? TransitionType.inFromRight,
      // routeSettings需要在对应页面接收:ModalRoute.of(context)?.settings.arguments;
      routeSettings: RouteSettings(
        arguments: arguments,
      ),
    );
  }

  // 无context replase
  static void replase(String path,
      {bool replace = true, bool clearStack = false, Object? arguments}) {
    Routes.router.navigateTo(
      navigatorKey.currentContext!,
      path,
      replace: replace,
      clearStack: clearStack,
      transition: TransitionType.inFromRight,
      // routeSettings需要在对应页面接收:ModalRoute.of(context)?.settings.arguments;
      routeSettings: RouteSettings(
        arguments: arguments,
      ),
    );
  }

  // 无context,清空路由栈跳转,一般用于跳转首页这种情况
  static void switchTab(String path,
      {bool replace = false, bool clearStack = true, Object? arguments}) {
    Routes.router.navigateTo(
      navigatorKey.currentContext!,
      path,
      replace: replace,
      clearStack: clearStack,
      transition: TransitionType.inFromRight,
      // routeSettings需要在对应页面接收:ModalRoute.of(context)?.settings.arguments;
      routeSettings: RouteSettings(
        arguments: arguments,
      ),
    );
  }

  // 无context返回,并指定路由返回多少层,默认返回上一页面, 返回带参数params
  static void back({int count = 1, Object? params}) {
    NavigatorState state = Navigator.of(navigatorKey.currentContext!);
    while (count-- > 0) {
      state = state..pop(params);
    }
  }
}

main.dart 配置

dart 复制代码
import 'package:planx_app/router/navigator_util.dart';
import 'package:planx_app/router/routes.dart';
// ...
MaterialApp(
  // ...
  // 配置路由
  onGenerateRoute: Routes.router.generator,
  // 指定路由的全局key
  navigatorKey: navigatorKey,
);

使用

dart 复制代码
NavigatorUtil.push(Routes.routerPage);

传递参数

一、传递params参数

  • 新建路由接收参数页面

router_params_page.dart

dart 复制代码
class RouterParamsPage extends StatelessWidget {
  const RouterParamsPage({Key? key, required this.content}) : super(key: key);
  // 用来接收路由传递过来的参数
  final String content;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      //....
      body: Center(
        child: Text(content), // 将参数显示到页面
      ),
    );
  }
}
  • 配置路由

lib/router/routes.dart

dart 复制代码
class Routes {
	//...
  // 路由传递参数页面
  static String routerParamPage = "/routerParam";
  static _initRouter() {
    // ...
    // 路由传递参数页面
    router.define(routerParamPage,
        handler: Handler(handlerFunc: (_, Map<String, dynamic> params) {
      // 获取路由参数
      String routerParam = params["content"]?[0];
      return RouterParamsPage(content: routerParam);
    }));
  }
	// ...
}

使用:路由跳转

  • 相当于直接在url后面拼接参数
dart 复制代码
// 传递参数
NavigatorUtil.push('${Routes.routerParamPage}?content=params11111');

参数带有特殊字符和中文时无法接收(比如: "www.baidu.com")

  • 这种情况需要考虑进行encode这样保证参数正常
  • 且通过上述的方法传递参数,每次都要拼接,并不优雅,我们顺便进行改造一下
改造NavigatorUtil方法,加密参数
  • 以下封装是完整版本

lib/router/navigator_util.dart 加密

dart 复制代码
import 'dart:convert';
import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
import 'package:planx_app/router/routes.dart';

// 全局key,用于无context跳转的情况
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();

class NavigatorUtil {
  // 这里进行加密
  // 处理url参数拼接
  static String _getPathParams({Map<String, String>? params, path}) {
    if (params != null) {
      // Utf8Encoder,解决参数有特殊字符,中文不能传递的情况
      String p = params.entries
          .map((e) =>
              '${e.key}=${jsonEncode(const Utf8Encoder().convert(e.value))}')
          .join('&');
      path = '$path?$p';
    }
    return path;
  }

  // 无context跳转
  static void push(
    String path, {
    Map<String, String>? params,
    bool replace = false,
    bool clearStack = false,
    Object? arguments,
    TransitionType? transition,
  }) {
    // 拼接params参数
    path = _getPathParams(params: params, path: path);
    Routes.router.navigateTo(
      navigatorKey.currentContext!,
      path,
      replace: replace,
      clearStack: clearStack,
      transition: transition ?? TransitionType.inFromRight,
      // routeSettings需要在对应页面接收:ModalRoute.of(context)?.settings.arguments;
      routeSettings: RouteSettings(
        arguments: arguments,
      ),
    );
  }

  // 无context replase
  static void replase(
    String path, {
    Map<String, String>? params,
    bool replace = true,
    bool clearStack = false,
    Object? arguments,
  }) {
    // 拼接params参数
    path = _getPathParams(params: params, path: path);
    Routes.router.navigateTo(
      navigatorKey.currentContext!,
      path,
      replace: replace,
      clearStack: clearStack,
      transition: TransitionType.inFromRight,
      // routeSettings需要在对应页面接收:ModalRoute.of(context)?.settings.arguments;
      routeSettings: RouteSettings(
        arguments: arguments,
      ),
    );
  }

  // 无context,清空路由栈跳转,一般用于跳转首页这种情况
  static void switchTab(
    String path, {
    Map<String, String>? params,
    bool replace = false,
    bool clearStack = true,
    Object? arguments,
  }) {
    // 拼接params参数
    path = _getPathParams(params: params, path: path);
    Routes.router.navigateTo(
      navigatorKey.currentContext!,
      path,
      replace: replace,
      clearStack: clearStack,
      transition: TransitionType.inFromRight,
      // routeSettings需要在对应页面接收:ModalRoute.of(context)?.settings.arguments;
      routeSettings: RouteSettings(
        arguments: arguments,
      ),
    );
  }

  // 无context返回,并指定路由返回多少层,默认返回上一页面, 返回带参数params
  static void back({int count = 1, Object? arguments}) {
    NavigatorState state = Navigator.of(navigatorKey.currentContext!);
    while (count-- > 0) {
      state = state..pop(arguments);
    }
  }
}
解码
  • 在路由定义位置解码

lib/router/routes.dart

dart 复制代码
  // 路由传递参数页面
    router.define(routerParamPage,
        handler: Handler(handlerFunc: (_, Map<String, dynamic> params) {
      // 获取路由参数
      String routerParam = _decodeParams(params["content"]?[0]);
      return RouterParamsPage(content: routerParam);
    }));

//...
  ///字符串解码,中文不能传递等问题
  static _decodeParams(String params) {
    List<int> list = [];
    jsonDecode(params).forEach(list.add);
    return const Utf8Decoder().convert(list);
  }

使用:

dart 复制代码
// 传递参数
NavigatorUtil.push(Routes.routerParamPage, params: {"content": "https://www.bd的收费吗,是打开就好aidu.com"});

二、传递类实例参数

  • 使用上面的NavigatorUtil方法,我们已经可以传递类参数了

使用页面:

dart 复制代码
// 传递参数,arguments可以接收一个类作为参数,Person是自己定义的类
NavigatorUtil.push(Routes.routerInstancePage,arguments: Person(name: "terry", age: 40));

接收,需要在build中接收

dart 复制代码
Widget build(BuildContext context) {
  // 接收参数
  Person p = (ModalRoute.of(context)?.settings.arguments as Person);
  return Scaffold(
    appBar: AppBar(title: Text('路由传递类参数')),
    body: Center(
      child: Column(
        children: [
          Text('ddd'),
          Text('姓名${p.name}'),
          Text('年龄${p.age}'),
        ],
      )),
  );
}
相关推荐
仰望星空的小猴子2 分钟前
React18和React19新特性
前端
小码哥_常4 分钟前
Android新航标:Navigation 3为何成为变革先锋?
前端
SuperEugene4 分钟前
Vue状态管理扫盲篇:状态管理中的常见坑 | 循环依赖、状态污染与调试技巧
前端·vue.js·面试
骑着小黑马5 分钟前
从 Electron 到 Tauri 2:我用 3.5MB 做了个音乐播放器
前端·vue.js·typescript
aykon6 分钟前
DataSource详解以及优势
前端
Mintopia6 分钟前
戴了 30 天智能手环后,我才发现自己一直低估了“睡眠”
前端
leolee186 分钟前
react redux 简单使用
前端·react.js·redux
仰望星空的小猴子7 分钟前
常用的Hooks
前端
天才熊猫君8 分钟前
Vue Fragment 锚点机制
前端
米丘8 分钟前
Git 常用操作命令
前端