likes
comments
collection
share

Flutter 路由模块化 - flutter_mixin_router

作者站长头像
站长
· 阅读数 47

库说明

flutter_mixin_router 库与其说是一个路由框架,还不如称之为一种思想,利于Dart的mixin特性,参考flutter源码中WidgetsFlutterBinding所总结出来的。 库本身代码核心类仅仅只有两个MixinRouterContainerMixinRouterInterceptContainer。前者用于粘合各模块的PageRoute列表,后者用于拦截PageRoute跳转, 比如拦截用户未登录情况下打开个人中心页面。

使用说明

项目结构如下:


 --- Home                           : 大厅业务模块
 
  ---- home_page_1.dart             : 大厅页面1
  
  ---- home_page_2.dart             : 大厅页面2
  
  ---- home_router_table.dart       : 使用mixin_router创建的文件,用于聚合该模块所有路由,即:大厅子路由表
  
 --- Mine                           : 个人业务模块     
 
  ---- mine_page.dart               : 个人页面1
  
  ---- mine_router_table.dart       : 使用mixin_router创建的文件,用于聚合该模块所有路由,即:个人子路由表
 
 main.dart                          : 启动文件(entry-point)
 
 app_router_center.dart             : 使用mixin_router创建的文件,用于聚合所有模块(大厅业务模块  个人业务模块),即:路由总表

页面相关的代码这里就不再说明了,重点文件main.dartapp_router_center.darthome_router_table.dartmine_router_table.dart

main.dart:

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Mixin Route Test',
      //配置初始化路由,建议定义静态字段
      initialRoute: '/home_page_1',
      //从路由总表中获取App所有路由
      routes: AppRouterCenter.share.installRouters(),
    );
  }
}

app_router_center.dart


//使用mixin机制,将各路由模块组装
class AppRouterCenter extends MixinRouterInterceptContainer
    with HomeRouterTable, MineRouterTable {
  AppRouterCenter._();

  static final AppRouterCenter _instance = AppRouterCenter._();

  static AppRouterCenter get share => _instance;
}

home_router_table.dart


//使用mixin定义大厅路由子表
mixin HomeRouterTable on MixinRouterContainer {
  @override
  Map<String, WidgetBuilder> installRouters() {
    Map<String, WidgetBuilder> superRouteList = super.installRouters();
    //添加本模块路由
    Map<String, WidgetBuilder> routeList = {
      '/home_page_1': (context) => Home1Page(),
      '/home_page_2': (context) => Home2Page(),
    };
    routeList.addAll(superRouteList);
    return routeList;
  }
}

mine_router_table.dart


//使用mixin定义个人路由子表,与大厅路由子表定义不同,此处继承MixinRouterInterceptContainer,支持拦截
//而 MixinRouterInterceptContainer extends MixinRouterContainer
mixin MineRouterTable on MixinRouterInterceptContainer {

  @override
  Map<String, WidgetBuilder> installRouters() {
    //注册路由拦截,return true 表示消费本次跳转,否则进行路由跳转
    registerRouteInterceptor('/mine_page', (context, pageName, pushType,
        {arguments, predicate}) {
      if (isLogin) {
        return false;
      }
      print('toLogin');
      return true;
    });
    Map<String, WidgetBuilder> superRouteList = super.installRouters();
    //添加本模块路由
    Map<String, WidgetBuilder> routeList = {
      '/mine_page': (context) => MinePage(),
    };
    routeList.addAll(superRouteList);
    return routeList;
  }
}

打开指定页面:

//可配置打开router的方式,pushName, pushReplacementNamed...
//可配置打开router的参数
AppRouteCenter.share.openPage(context, '/mine_page', ...)

页面参数获取

String? name = getMixinArg(context)?['name'];
int? age = getMixinArg(context)?['age'];

扩展

  • 内置扩展

    如果AppRouterCenter extends UriRouterInterceptContainer,则上面打开指定页面的方式,可以支持Uri,

    AppRouteCenter.share.urlToPage(context, 'appscheme://mine_page?name=1&age=2')
    
    String? name = getMixinArg(context)?['name'];
    
    //通过uri的方式打开页面,参数都是string类型
    String? age = getMixinArg(context)?['age'];
    
  • 自定义扩展

    开发者可参考UriRouterInterceptContainer自定Container,并使得 AppRouterCenter extends 自定义Container


到此为止,flutter_mixin_router说明已经结束,但是使用该方案,还是会存在大量的模板代码,但是可以利用Dart的build_runner生成代码,简化 flutter_mixin_router的使用。

集成


# 以下xxx替换成最新版本号

dependencies:
  ...
  #添加
  flutter_mixin_router_ann: xxx
  #添加
  flutter_mixin_router: xxx

dev_dependencies:
  ...
  #添加
  build_runner: 2.1.8
  #添加
  flutter_mixin_router_gen: xxx

使用

项目结构说明:


 --- Home                           : 大厅业务模块
 
  ---- home_page_1.dart             : 大厅页面1
  
  ---- home_page_2.dart             : 大厅页面2
  
 --- Mine                           : 个人业务模块     
 
  ---- mine_page.dart               : 个人页面1
 
 main.dart                          : 启动文件(entry-point)
 
 app_router_center.dart             : 使用mixin_router创建的文件,用于聚合所有模块(大厅业务模块  个人业务模块),即:路由总表

flutter_mixin_router 说明中的项目结构对比,每个模块不再需要定义子路由表文件,改由flutter_mixin_router_gen生成。

使用flutter_mixin_router_gen需要关注三点:总路由表 app_router_center.dart 文件编写、页面路由注册、拦截路由注册。

app_router_center.dart:


//定义大厅子路由表名称
const String HOME_ROUTER_TABLE = 'HomeRouterTable';
//定义个人子路由表名称
const String MINE_ROUTER_TABLE = 'MineRouterTable';

//向总路由表注册各子路由表
//tDescription: 仅仅作为生成类的注释
@RouterTableList(
  tableList: [
    RouterTable(tName: HOME_ROUTER_TABLE, tDescription: '大厅路由模块'),
    RouterTable(tName: MINE_ROUTER_TABLE, tDescription: '个人路由模块'),
  ],
)
//with HomeRouterTable, MineRouterTable,即上面声明的两个路由表的名字
class AppRouterCenter extends UriRouterInterceptContainer
    with HomeRouterTable, MineRouterTable {
  AppRouterCenter._();

  static final AppRouterCenter _instance = AppRouterCenter._();

  static AppRouterCenter get share => _instance;
}

页面注册:

//定义路由页面,tName 代表该路由属于哪个路由子表
@MixinRoute(tName: HOME_ROUTER_TABLE, path: '/home_page_1')
class Home1Page extends StatelessWidget {
  ...
}

拦截路由注册:

@MixinRoute(tName: MINE_ROUTER_TABLE, path: '/mine_page')
class MinePage extends StatelessWidget {
  const MinePage({Key? key}) : super(key: key);

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

//定义路由拦截,该注解使用在方法上,方法有以下两个约束:
//1、作为顶级元素声明在文件中
//2、方法的参数和返回值固定
@MixinInterceptRoute(tName: MINE_ROUTER_TABLE, path: '/mine_page')
bool interceptorMinePage(context, pageName, pushType, {arguments, predicate}) {
  if (isLogin) {
    return false;
  }
  print('toLogin');
  return true;
}

生成文件

  # 清除增量编译缓存
  flutter packages pub run build_runner clean

  # 重新生成代码
  flutter packages pub run build_runner build --delete-conflicting-outputs

生成的文件与被RouterTableList注解的文件X同级。


转载自:https://juejin.cn/post/7076284057423708197
评论
请登录