Flutter路由管理插件route_tree的使用

发布于 1周前 作者 caililin 来自 Flutter

Flutter路由管理插件route_tree的使用

RouteTree

RouteTree 是一个用于解析 URI 路径的通用库。

RouteTree 是一个通用路由库,它使得基于 URI 的路径段实现路由逻辑变得非常简单。这通过嵌套 Segment 节点来构建一个树状结构,类似于你在 Flutter 应用程序中看到的 Widget 树。

快速示例

final router = Segment.root<String>(
  create: (context) => "home",
  createError: (context) => "Error!",
  children: [
    Segment.path(
      name: "first_path",
      create: (context) => "routed to first_path",
    ),
    Segment.path(
      name: "second_path",
      create: (context) => "routed to second_path",
      children: [
        Segment.param(
          parser: const UintParser("id"),
          create: (context) => "routed to /second_path/${context["id"]}",
        ),
      ],
    ),
  ],
);

assert(router.route(Uri.parse("/second_path/12")) == "routed to second_path/12");

注意模板参数,该参数表示 RootSegment.route 将返回的数据类型。这使得 route_tree 非常灵活。

它如何工作

这个库的基本构建块是 SegmentsSegmentParsersParseContext

Segments

Segments 是 route_tree 中的 Widget。每个 Segment 代表一个可能的路径段,可以作为路由的一部分。由于它是模板化的,因此可以用多种方式使用,例如在 Flutter 应用程序中进行路由或在后端选择正确的函数来处理传入的 HTTP 请求。抽象类 Segment 包含几个工厂构造方法,以简化查找正确的 Segment

RootSegment 或 Segment.root

任何 route_tree 的根节点。

定义了 “/” 路由、根错误处理器以及一组可以用来断言路由树某些属性的 SegmentVerifier

默认情况下,RootSegments 包含 findConflictingParamKeys,如果路由树包含重复的参数键(如 /users/{id}/edit/{id}),则会返回错误。

/// 匹配 "/"
final router = Segment.root<String>(
  create: (context) => "home",
  createError: (context) => "root error",
  children: [
    ...
  ],
);

PathSegment 或 Segment.path

你最常使用的 Segment。它定义了一个简单的文字路径段。内部包含在具有 LiteralParserSegment 的子节点(默认只适用于 PathSegment)被包含在一个 Map&lt;String, PathSegment&gt; 中,以便于快速查找相应的路径段。

Segment.root<String>(
  ...
  children: [
    /// 匹配 "/about"
    Segment.path(
      name: "about",
      create: (context) => "about",
    ),
    /// 匹配 "/settings/*",但不匹配 "/settings" 本身,因为 [create] 为 null
    Segment.path(
      name: "settings",
      children: [
        /// 匹配 "/settings/privacy"
        Segment.path(
          name: "privacy",
          create: (context) => "privacy",
        ),
      ],
    ),
  ],
);

RegExpPathSegment 或 Segment.regExpPath

用于定义一个或多个路径,这些路径应该由一个 Segment 使用正则表达式匹配。

Segment.root<String>(
  ...
  children: [
    /// 匹配任何由字母组成的路径段
    Segment.regExpPath(
      regExp: RegExp(r"[a-zA-Z]+"),
      create: (context) => "letter path",
    ),
  ],
);

ParamSegment 或 Segment.param

用于定义路径参数。如果 URI 的段匹配,则将匹配值添加到 ParseContext 中,可以从 ParseContext 中查询该值。

Segment.root<String>(
  create: (context) => "home",
  createError: (context) => "error!",
  children: [
    /// 匹配 "/users/*",因为 [create] 为 null
    Segment.path(
      name: "users",
      children: [
        /// 匹配 "/users/{id}",其中 {id} 是由 [UintParser] 定义的任何非负整数。
        Segment.param(
          parser: const UintParser("id"),
          create: (context) => context["id"] as String,
        ),
      ],
    ),
  ],
);

RegExpParamSegment 或 Segment.regExpParam

考虑像 Twitter 这样的 URL,例如 https://twitter.com/{name},其中 name 可以是任何单词,而一个假设的 Twitter 客户端显然不能硬编码所有可能的名字。这就是这个 Segment 发挥作用的地方。它可以用来定义一个路径参数,该参数匹配提供的正则表达式,并将其注入到 ParseContext 中,可以从 ParseContext 中查询该值。

final router = Segment.root<String>(
  create: (context) => "home",
  createError: (context) => "error!",
  children: [
    /// 匹配任何由字母组成的路径段
    Segment.regExpParam(
      parser: RegExpParamParser.forward(
        key: "name",
        regExp: RegExp(r"\w+"),
      ),
      create: (context) => context["name"] as String,
    ),
  ],
);

assert(router.route(Uri.parse("/flutterdev")) == "flutterdev");

SegmentParsers

实际的解析逻辑,用于查找正确的段,委托给 SegmentParser 的实例。预定义的解析器包括:

  • SegmentParser.withFunction,它接受一个 Parser 函数,可用于快速定义自定义 SegmentParses
  • LiteralParser,主要用于 PathSegment (& Segment.path),并按文字匹配路径段
  • RegExpParser,根据正则表达式匹配路径段
  • ParamParser,是 SegmentParser 的子类,也是注入匹配项到 ParseContext 的解析器基类
  • ParamParser.withFunction,可用于快速定义自定义 ParamParsers
  • RegExpParamParser,类似于 RegExpParser,但也会将成功的匹配项注入到 ParseContext
  • IntParserUintParser,分别匹配整数和非负整数。后者对 id 路径参数很有用。

ParseContext

ParseContext 包含初始 URI 以及当前路由中的任何路径参数。当路径匹配时调用的 create 函数会传递该上下文。

示例代码

import 'package:route_tree/route_tree.dart';

void main() {
  final router = Segment.root<String>(
    create: (context) => 'home',
    createError: (context) => 'Error!',
    children: [
      Segment.path(
        name: 'first_path',
        create: (context) => 'routed to first_path',
      ),
      Segment.path(
        name: 'second_path',
        create: (context) => 'routed to second_path',
        children: [
          Segment.param(
            parser: const UintParser('id'),
            create: (context) => 'routed to /second_path/${context['id']}',
          ),
        ],
      ),
    ],
  );

  assert(
      router.route(Uri.parse('/second_path/12')) == 'routed to second_path/12');
}

更多关于Flutter路由管理插件route_tree的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter路由管理插件route_tree的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,关于Flutter中的路由管理插件route_tree的使用,这里提供一个简单的代码案例来展示其基本功能。route_tree是一个用于Flutter的路由管理库,它提供了一种声明式的方式来定义应用中的路由结构。

首先,确保你的pubspec.yaml文件中已经添加了route_tree依赖:

dependencies:
  flutter:
    sdk: flutter
  route_tree: ^最新版本号  # 替换为实际最新版本号

然后运行flutter pub get来安装依赖。

以下是一个使用route_tree的简单示例:

main.dart

import 'package:flutter/material.dart';
import 'package:route_tree/route_tree.dart';
import 'home_page.dart';
import 'details_page.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routeInformationParser: RouteTreeParser(),
      routerDelegate: RootRouterDelegate(
        // 定义路由树
        child: RouteTreeNode(
          path: '/',
          builder: (_, __) => HomePage(),
          children: [
            RouteTreeNode(
              path: 'details',
              builder: (_, args) => DetailsPage(id: args['id'] as int),
            ),
          ],
        ),
      ),
    );
  }
}

home_page.dart

import 'package:flutter/material.dart';
import 'package:route_tree/route_tree.dart';

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Home Page')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            // 导航到详情页面,并传递参数
            context.push('/details', arguments: {'id': 123});
          },
          child: Text('Go to Details'),
        ),
      ),
    );
  }
}

details_page.dart

import 'package:flutter/material.dart';

class DetailsPage extends StatelessWidget {
  final int id;

  DetailsPage({required this.id});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Details Page')),
      body: Center(
        child: Text('Details for ID: $id'),
      ),
    );
  }
}

解释

  1. main.dart:这是应用的入口文件。我们使用了MaterialApp.router来配置路由,并指定了routeInformationParserrouterDelegateRootRouterDelegateroute_tree提供的一个委托,用于处理路由树的逻辑。

  2. RouteTreeNode:在RootRouterDelegate中,我们定义了一个路由树。根节点是HomePage,它有一个子节点DetailsPage。子节点的路径是/details,并且可以通过arguments接收参数。

  3. home_page.dartHomePage包含一个按钮,点击按钮时会触发导航到详情页面,并传递一个参数id

  4. details_page.dartDetailsPage接收一个id参数,并在页面上显示。

这个简单的示例展示了如何使用route_tree进行路由管理,并通过路径和参数在页面之间进行导航。你可以根据需要扩展这个示例,添加更多的页面和复杂的路由结构。

回到顶部