Flutter Web:使用命名路线导航URL
命名路由可以用来在Flutter移动应用内部的页面之间导航,但它们也适用于Flutter Web应用中的URL。这篇文章解释了如何将命名路由添加到您的应用程序中,以及如何自定义它们,以在路由内部进行模式匹配。
定义命名路由
通过在MaterialApp类中定义命名路线,可以将其添加到您的应用程序中。MaterialApp.routes 属性包含了一张地图,列出了每个命名的路由及其相关的显示部件。MaterialApp.initialRoute 属性决定了应用程序启动时显示的路由。因此,initialRoute需要在route属性中定义。例如:
MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => HomePage(),
'/overview': (context) => OverviewPage(),
},
);
一个好的做法是把命名的路由放在静态变量里, 例如, 放在widgets本身:
class OverviewPage extends StatelessWidget {
static const String route = '/overview';
}
下一步,重构MaterialApp.routes,将命名的路由定义为静态变量。
MaterialApp(
initialRoute: HomePage.route,
routes: {
HomePage.route: (context) => HomePage(),
OverviewPage.route: (context) => OverviewPage(),
},
);
在页面之间导航
要从一个页面导航到另一个页面,只需将命名的路径推到导航器上即可。
RaisedButton(
onPressed: () {
Navigator.of(context).pushNamed(OverviewPage.route);
},
)
在DartPad上可以看到一个完整的交互式示例。如果你自己构建并运行网络应用,你也可以在网络浏览器中输入/#/overview。这样就会将名为overview的路由推送到Navigator,并将你带到OverviewPagewidget,你可以在下面的GIF中看到。
在DartPad上查看完整的交互式示例
动态URL的路由逻辑
您可能需要解决更多复杂的情况,比如在路由中进行模式匹配,以允许动态URL。为了扩展这个例子,假设你在概览页上有许多不同的文章。对于每一篇文章,你希望能够直接通过URL进行导航:
/#/article/a-very-interesting-article
/#/article/newsworthy-news
要为MaterialApp中的所有文章定义命名的路由,并不能很好地扩展。对于这样的动态情况,你需要做一些更自定义的事情。截止到目前,Flutter的稳定通道是在v1.12版本,还没有简单的方法,不过有计划在新的Navigator中增加对更高级路由的支持。
目前你可以使用外部包,比如Fluro包就提供了更高级的路由。它为你提供了路由中的通配符模式匹配,以及URL中查询字符串的解析。可能还有很多其他可用的包,所以请在评论中留下你最喜欢的包的名字。
如果你愿意接受挑战,你也可以通过使用MaterialApp.onGenerateRoute属性来获得动态路由。使用这个属性来编写路由逻辑,当命名的路由不在MaterialApp.routes里面时,就可以使用这个属性。
对于每个路由,定义一个带有 RegEx 模式的 Path。如果命名的路由与该模式匹配,则返回相关的小组件。接下来,定义Path类来支持:
class Path {
const Path(this.pattern, this.builder);
final String pattern;
final Widget Function(BuildContext, String) builder;
}
对于概览页和主页路由,它很简单,看起来和你之前的类似。下面的示例创建了一个RegEx模式,该模式匹配一个slug(带破折号的小写字母),用于查找相应的文章。
static List<Path> paths = [
Path(
r'^/article/([\w-]+)$',
(context, match) => Article.getArticlePage(match),
),
Path(
r'^' + OverviewPage.route,
(context, match) => OverviewPage(),
),
Path(
r'^' + HomePage.route,
(context, match) => HomePage(),
),
];
剩下的就是为MaterialApp创建一个onGenerateRoute函数。如果路径列表中定义了当前的命名路由(settings.name),则返回相关的widget。确保在RegEx中传递任何命名匹配(在本例中是slug)。如果没有找到匹配项,就简单地返回null,WidgetsApp.onUnknownRoute被调用来处理这种情况。
static Route<dynamic> onGenerateRoute(RouteSettings settings) {
for (Path path in paths) {
final regExpPattern = RegExp(path.pattern);
if (regExpPattern.hasMatch(settings.name)) {
final firstMatch = regExpPattern.firstMatch(settings.name);
final match = (firstMatch.groupCount == 1) ? firstMatch.group(1) : null;
return MaterialPageRoute<void>(
builder: (context) => path.builder(context, match),
settings: settings,
);
}
}
// If no match is found, [WidgetsApp.onUnknownRoute] handles it.
return null;
}
确保在MaterialApp类中定义onGenerateRoute函数;你已经用Flutter实现了动态URL,使用了命名的路由!你可以在DartPad上看到一个完整的交互式例子。
在DartPad上查看完整的交互式示例
结束语
无论你是选择为路由编写自己的自定义逻辑,还是简单地使用MaterialApp中存在的路由支持,当使用命名路由时,你都可以通过网络上的Flutter应用默认获得URL支持。实现命名路由还可以确保你将展现逻辑与路由逻辑解耦,从而减少代码重复。 请在评论中告诉我你在你的应用中使用了什么解决方案,是自己编写自定义逻辑还是使用外部包。
作者:Sunbreak
来源:掘金