如何在Flet中实现多页面切换?附现有代码求助
解决方案:Flet多页面切换与组件复用
先修正原代码里的两处小问题:
- CustomAppBar中
self.appbar_items未定义,需把appbar_items设为实例变量才能在登录后修改菜单 self.store没有实现,临时用列表模拟用户存储功能
以下是完整的实现代码,包含3个可切换的页面,每个页面都复用自定义的AppBar和NavigationDrawer:
import flet as ft from flet import ( RouteChangeEvent, View, AppBar, PopupMenuItem, PopupMenuButton, Icon, icons, Text, colors, Container, margin, TextField, AlertDialog, ElevatedButton, Column ) class CustomNavigationDrawer(ft.NavigationDrawer): def __init__(self, page): super().__init__() self.page = page # 初始化抽屉选项,每个选项对应一个路由 self.controls = [ ft.Container(height=12), ft.NavigationDrawerDestination( label="页面1", icon=ft.icons.DOOR_BACK_DOOR_OUTLINED, selected_icon_content=ft.Icon(ft.icons.DOOR_BACK_DOOR), on_click=lambda e: self.switch_route("/page1") ), ft.Divider(thickness=2), ft.NavigationDrawerDestination( icon_content=ft.Icon(ft.icons.MAIL_OUTLINED), label="页面2", selected_icon=ft.icons.MAIL, on_click=lambda e: self.switch_route("/page2") ), ft.NavigationDrawerDestination( icon_content=ft.Icon(ft.icons.PHONE_OUTLINED), label="页面3", selected_icon=ft.icons.PHONE, on_click=lambda e: self.switch_route("/page3") ), ] def switch_route(self, route): # 切换路由并关闭抽屉 self.page.route = route self.open = False self.page.update() def add_custom_control(self, control): self.controls.append(control) class User: def __init__(self, name, password): self.name = name self.password = password class CustomAppBar(AppBar): def __init__(self, title_text: str, page): self.page = page self.users = [] # 模拟用户存储 login_profile_button = PopupMenuItem(text="Log in", on_click=self.login) self.appbar_items = [ login_profile_button, PopupMenuItem(), # divider PopupMenuItem(text="Settings"), ] super().__init__( leading=Icon(None), leading_width=-1, title=Text(title_text, font_family="Pacifico", size=32, text_align="start"), center_title=False, toolbar_height=75, bgcolor=colors.LIGHT_BLUE_ACCENT_700, actions=[ Container( content=PopupMenuButton(items=self.appbar_items, tooltip="Menu rápido"), margin=margin.only(left=50, right=25), ) ], ) def login(self, e): def close_dlg(e): if user_name.value == "" or password.value == "": user_name.error_text = "请输入用户名" password.error_text = "请输入密码" self.page.update() return user = User(user_name.value, password.value) # 检查用户是否已存在 existing_user = next((u for u in self.users if u.name == user.name), None) if not existing_user: self.users.append(user) self.page.client_storage.set("current_user", user.name) dialog.open = False # 更新登录按钮为用户信息 self.appbar_items[0] = PopupMenuItem(text=f"{user.name}'s Profile") self.page.update() user_name = TextField(label="Usuário") password = TextField(label="Password", password=True) dialog = AlertDialog( title=Text("Identifique-se"), content=Column( [user_name, password, ElevatedButton(text="Login", on_click=close_dlg)], tight=True, ), on_dismiss=lambda e: print("Modal dialog dismissed!"), ) self.page.dialog = dialog dialog.open = True self.page.update() def add_appbar_item(self, item): self.appbar_items.append(item) def main(page: ft.Page): page.title = 'RD STATION' page.theme_mode = "dark" # 定义页面生成函数,复用AppBar和Drawer def get_page_view(title, route): appbar = CustomAppBar(title, page) appbar.add_appbar_item(PopupMenuItem(text="New Item")) drawer = CustomNavigationDrawer(page) # 添加自定义抽屉选项 drawer.add_custom_control(ft.NavigationDrawerDestination( icon_content=ft.Icon(ft.icons.SETTINGS_OUTLINED), label="Configurações", selected_icon=ft.icons.SETTINGS, on_click=lambda e: print("设置页面待实现") )) # 页面主体内容,每个页面不同 if route == "/page1": content = Text("这是页面1的内容", size=24) elif route == "/page2": content = Column([Text("页面2内容", size=24), ElevatedButton(text="页面2按钮")]) elif route == "/page3": content = Container( content=Text("页面3内容", size=24), bgcolor=colors.BLUE_GREY_100, padding=20, border_radius=10 ) else: content = Text("默认页面", size=24) return View( route, [ ft.IconButton( icon=ft.icons.MENU_SHARP, icon_color="blue400", icon_size=25, tooltip="Clique para abrir", on_click=lambda e: (setattr(drawer, "open", True), page.update()) ), content ], appbar=appbar, drawer=drawer ) # 路由切换处理函数 def on_route_change(e: RouteChangeEvent): page.views.clear() # 根据当前路由加载对应页面 if e.route == "/page1": page.views.append(get_page_view("页面1", "/page1")) elif e.route == "/page2": page.views.append(get_page_view("页面2", "/page2")) elif e.route == "/page3": page.views.append(get_page_view("页面3", "/page3")) else: # 默认跳转到页面1 page.route = "/page1" page.views.append(get_page_view("页面1", "/page1")) page.update() # 监听路由变化 page.on_route_change = on_route_change # 初始化路由 page.go("/page1") ft.app(main)
关键实现说明:
组件复用优化:
- CustomNavigationDrawer初始化时传入page实例,绑定每个选项的点击事件,点击后直接切换路由并关闭抽屉
- CustomAppBar也传入page实例,修复了登录后菜单更新的逻辑,用列表模拟用户存储
页面切换逻辑:
- 使用Flet的
View类定义每个页面,每个View包含独立的AppBar、Drawer和主体内容 - 通过
on_route_change事件监听路由变化,根据路由加载对应的View - 初始化时默认跳转到/page1
- 使用Flet的
抽屉与菜单功能:
- 每个页面的抽屉都保留了原有的选项,还可以通过
add_custom_control添加自定义选项 - AppBar的登录功能修复了原代码的错误,登录后会更新菜单显示用户信息
- 每个页面的抽屉都保留了原有的选项,还可以通过
内容的提问来源于stack exchange,提问作者Elias Coutinho
相关产品推荐
相关产品推荐

