0%

【文章翻譯】Flutter web: Navigating URLs using named routes

【文章內容使用 Gemini 1.5 Pro 自動產生】

Flutter 網頁:使用命名路由導航 URL

命名路由可以用於導航 Flutter 行動應用程式中的頁面之間,但它們也適用於 Flutter 網頁應用程式中的 URL。本文將說明如何在您的應用程式中加入命名路由,以及如何自訂它們,以便在路由中進行模式比對。

定義命名路由

您可以透過在 MaterialApp 類別中定義命名路由來將它們加入到您的應用程式中。MaterialApp.routes 屬性包含一個映射,列出每個命名路由及其關聯的顯示 Widget。MaterialApp.initialRoute 屬性決定應用程式啟動時顯示的路由。因此,initialRoute 需要在 routes 屬性中定義。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: '/overview',
routes: {
'/overview': (context) => OverviewPage(),
},
);
}
}

為了保持程式碼的組織性,將命名路由放在靜態變數中是一個好習慣,例如,放在 Widget 本身:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class OverviewPage extends StatelessWidget {
static const String routeName = '/overview';

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Overview'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Overview Page',
style: TextStyle(fontSize: 20),
),
ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, ArticlePage.routeName);
},
child: Text('Go to article'),
),
],
),
),
);
}
}

接下來,使用現在定義為靜態變數的命名路由重新整理 MaterialApp.routes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: OverviewPage.routeName,
routes: {
OverviewPage.routeName: (context) => OverviewPage(),
},
);
}
}

在頁面之間導航

若要從一個頁面導航到另一個頁面,只需將命名路由推入導航器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class OverviewPage extends StatelessWidget {
// ...

@override
Widget build(BuildContext context) {
return Scaffold(
// ...
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
// ...
ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, ArticlePage.routeName);
},
child: Text('Go to article'),
),
],
),
),
);
}
}

您可以在 DartPad 上查看此範例的完整互動式版本。如果您自己 構建和運行應用程式以供網頁使用,您也可以在網頁瀏覽器中鍵入 /#/overview。這會將名為 overview 路由推送到 Navigator,並帶您前往 OverviewPage Widget,如以下 GIF 所示:

在 DartPad 上查看完整的互動式範例。

動態 URL 的路由邏輯

您可能需要處理比本文中提到的更複雜的場景,例如在路由中進行模式比對以允許動態 URL。為了擴展此範例,假設您在概覽頁面上有很多不同的文章。對於每篇文章,您都希望能夠透過 URL 直接導航:

1
2
/#/article/a-very-interesting-article
/#/article/newsworthy-news

MaterialApp 中為所有文章定義命名路由的可擴展性並不好。對於此類動態情況,您需要做一些更自訂的操作。截至撰寫本文時,Flutter 的穩定版本為 v1.12,沒有 簡單的方法 可以做到這一點,但 新的 Navigator 有計畫加入對更進階路由的支援。

目前,您可以使用一個外部套件,例如 Fluro 套件 提供更多進階路由。它為您提供了路由中的萬用字元模式比對,以及對 URL 中查詢字串的解析。可能還有許多其他可用的套件,因此請在留言中留下您最喜歡的套件名稱。

如果您想挑戰自己,也可以透過使用 MaterialApp.onGenerateRoute 屬性來獲取動態路由。使用此屬性來編寫當命名路由不在 MaterialApp.routes 中時的路由邏輯。

對於每個路由,請使用 RegEx 模式定義一個 Path。如果命名路由與模式匹配,則返回關聯的 Widget。接下來,定義 Path 類別以支援該操作:

1
2
3
4
5
6
class Path {
final String pattern;
final Function builder;

const Path({required this.pattern, required this.builder});
}

對於概覽頁面和首頁路由,它非常簡單,看起來與您之前使用的類似。以下範例建立了一個 RegEx 模式,該模式與 slug(帶有連字號的小寫字母)匹配,用於查找相應的文章:

1
2
3
4
5
6
List<Path> paths = [
Path(
pattern: r'/article/(?<slug>[\w-]+)',
builder: (context, matches) => ArticlePage(slug: matches['slug']),
),
];

剩下的就是為 MaterialApp 建立一個 onGenerateRoute 函數。如果目前的命名路由(settings.name)在 paths 列表中定義,則返回關聯的 Widget。確保將 RegEx 中的任何命名匹配項傳遞進去(在此範例中為 slug)。如果找不到匹配項,只需返回 nullWidgetsApp.onUnknownRoute 將被呼叫以處理這些情況:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
// ...
onGenerateRoute: (settings) {
for (Path path in paths) {
final regExp = RegExp(path.pattern);
final match = regExp.firstMatch(settings.name);
if (match != null) {
return MaterialPageRoute(
builder: (context) => path.builder(context, match.groups),
);
}
}
return null;
},
);
}
}

確保在 MaterialApp 類別中定義 onGenerateRoute 函數;您已經使用 Flutter 實作了動態 URL,使用命名路由!您可以 在 DartPad 上查看完整的互動式範例

在 DartPad 上查看完整的互動式範例。

結論

無論您是選擇為路由編寫自己的自訂邏輯,還是僅使用 MaterialApp 中現有的路由支援,您在使用命名路由時,Flutter 網頁應用程式都可以在預設情況下獲得 URL 支援。實作命名路由還可以確保您將呈現邏輯與路由邏輯解耦,從而減少程式碼重複。

請在留言中告訴我您在應用程式中使用什麼解決方案,無論是編寫自己的自訂邏輯還是使用外部套件。

祝您編碼愉快!


Flutter 網頁:使用命名路由導航 URL 最初發佈在 Flutter 上的 Medium,人們在那裡透過突出顯示和回應這個故事來繼續討論。