导航和路由
导航和路由是单页应用程序 (SPA) 的基本功能,它允许将应用程序用户界面组织成虚拟页面(视图)并在它们之间“导航”,而应用程序 URL 反映了应用程序的当前状态。
对于移动应用程序,导航和路由充当到特定应用程序部分的深层链接。
好吧,由于实现是基于Navigator 2.0 Flutter API 并且需要将 Flet 的“页面”抽象替换为“页面和视图” ,因此将导航和路由添加到 Flet 中花费了比预期更多的努力。Flutter 较新的导航和路由 API 具有重大改进,例如:
- 对历史堆栈的编程控制。
- 在 AppBar 中拦截对“返回”按钮的调用的简单方法。
- 与浏览器历史记录的强大同步。
探索上述示例的源代码:
import flet
from flet import AppBar, ElevatedButton, Page, Text, View, colors
def main(page: Page):
page.title = "Routes Example"
print("Initial route:", page.route)
def route_change(e):
print("Route change:", e.route)
page.views.clear()
page.views.append(
View(
"/",
[
AppBar(title=Text("Flet app")),
ElevatedButton("Go to settings", on_click=open_settings),
],
)
)
if page.route == "/settings" or page.route == "/settings/mail":
page.views.append(
View(
"/settings",
[
AppBar(title=Text("Settings"), bgcolor=colors.SURFACE_VARIANT),
Text("Settings!", style="bodyMedium"),
ElevatedButton(
"Go to mail settings", on_click=open_mail_settings
),
],
)
)
if page.route == "/settings/mail":
page.views.append(
View(
"/settings/mail",
[
AppBar(
title=Text("Mail Settings"), bgcolor=colors.SURFACE_VARIANT
),
Text("Mail settings!"),
],
)
)
page.update()
def view_pop(e):
print("View pop:", e.view)
page.views.pop()
top_view = page.views[-1]
page.go(top_view.route)
page.on_route_change = route_change
page.on_view_pop = view_pop
def open_mail_settings(e):
page.go("/settings/mail")
def open_settings(e):
page.go("/settings")
page.go(page.route)
flet.app(target=main, view=flet.WEB_BROWSER)
页面
页面路由是#
符号后的应用程序 URL 的一部分:
如果用户未在应用程序 URL 中设置默认应用程序路由,则为/
. /
例如/store
,所有路线都以 开头/authors/1/books/2
。
应用路由可以通过读取page.route
属性获取,例如:
import flet
from flet import Page, Text
def main(page: Page):
page.add(Text(f"Initial route: {page.route}"))
flet.app(target=main, view=flet.WEB_BROWSER)
获取应用程序 URL,打开一个新的浏览器选项卡,粘贴 URL,在#
to之后修改其部分/test
并按 Enter。您应该看到“初始路由:/test”。
每次更改 URL 中的路由(通过编辑 URL 或使用后退/前进按钮导航浏览器历史记录)时,Flet 都会调用page.on_route_change
事件处理程序:
import flet
from flet import Page, Text
def main(page: Page):
page.add(Text(f"Initial route: {page.route}"))
def route_change(route):
page.add(Text(f"New route: {route}"))
page.on_route_change = route_change
page.update()
flet.app(target=main, view=flet.WEB_BROWSER)
现在尝试更新 URL 哈希几次,然后使用后退/前进按钮!每次路由更改时,您应该会看到一条新消息添加到页面:
可以通过更新page.route属性以编程方式更改路线:
import flet
from flet import ElevatedButton, Page, Text
def main(page: Page):
page.add(Text(f"Initial route: {page.route}"))
def route_change(route):
page.add(Text(f"New route: {route}"))
def go_store(e):
page.route = "/store"
page.update()
page.on_route_change = route_change
page.add(ElevatedButton("Go to Store", on_click=go_store))
flet.app(target=main, view=flet.WEB_BROWSER)
单击“转到商店”按钮,您将看到应用程序 URL 已更改,并且在浏览器历史记录中推送了一个新项目。您可以使用浏览器“返回”按钮导航到上一条路线。
页面
Flet 的Page
现在不仅仅是一个页面,而是一个View
容器,它们像三明治一样层叠在一起:
视图集合代表导航器历史。页面具有page.views
访问视图集合的属性。
列表中的最后一个视图是页面上当前显示的视图。视图列表必须至少有一个元素(根视图)。
模拟页面更改之间的转换并在列表末尾page.route
添加一个新的。View
page.view
弹出集合中的最后一个视图并将路由更改为page.on_view_pop
事件处理程序中的“上一个”视图以返回。
建立对路线
要构建可靠的导航,程序中必须有一个位置,该位置根据当前路线构建视图列表。换句话说,导航历史堆栈(由视图列表表示)必须是路线的函数。
这个地方是page.on_route_change
事件处理程序。
让我们将所有内容放在一个完整的示例中,该示例允许在两个页面之间导航:
import flet
from flet import AppBar, ElevatedButton, Page, Text, View, colors
def main(page: Page):
page.title = "Routes Example"
def route_change(route):
page.views.clear()
page.views.append(
View(
"/",
[
AppBar(title=Text("Flet app"), bgcolor=colors.SURFACE_VARIANT),
ElevatedButton("Visit Store", on_click=lambda _: page.go("/store")),
],
)
)
if page.route == "/store":
page.views.append(
View(
"/store",
[
AppBar(title=Text("Store"), bgcolor=colors.SURFACE_VARIANT),
ElevatedButton("Go Home", on_click=lambda _: page.go("/")),
],
)
)
page.update()
def view_pop(view):
page.views.pop()
top_view = page.views[-1]
page.go(top_view.route)
page.on_route_change = route_change
page.on_view_pop = view_pop
page.go(page.route)
flet.app(target=main, view=flet.WEB_BROWSER)
尝试使用“访问商店”和“返回主页”按钮、后退/前进浏览器按钮、手动更改 URL 中的路径在页面之间导航 - 无论如何它都有效!:)
注意 为了在我们使用的页面之间“导航”
page.go(route)
- 一个更新的辅助方法page.route
,调用page.on_route_change
事件处理程序来更新视图,最后调用page.update()
.
注意page.on_view_pop
事件处理程序的使用。它在用户单击控件中的自动“返回”按钮时触发AppBar
。在处理程序中,我们从视图集合中删除最后一个元素并导航到视图的根“下方”。
路线
Flet 提供TemplateRoute
- 一个基于repath
库的实用程序类,它允许匹配类似 ExpressJS 的路由并解析它们的参数,例如/account/:account_id/orders/:order_id
.
TemplateRoute
非常适合路线更改事件:
troute = TemplateRoute(page.route)
if troute.match("/books/:id"):
print("Book view ID:", troute.id)
elif troute.match("/account/:account_id/orders/:order_id"):
print("Account:", troute.account_id, "Order:", troute.order_id)
else:
print("Unknown route")
您可以在此处阅读有关repath库支持的模板语法的更多信息。
URL 策略
Flet Web 应用程序支持两种配置基于 URL 的路由的方式:
- 散列(默认)- 读取和写入散列片段的路径。例如,
fletapp.dev/#/path/to/view
。 - 路径- 在没有哈希的情况下读取和写入路径。例如,
fletapp.dev/path/to/view
。
要更改 URL 策略,请使用方法route_url_strategy
参数flet.app()
,例如:
flet.app(target=main, route_url_strategy="path")
Flet Server 的 URL 策略可以使用FLET_ROUTE_URL_STRATEGY
环境变量进行配置,该变量可以设置为path
或者hash
(默认)。