在 NiceGUI 3.0+ 中,使用左侧抽屉进行页面切换适合轻量级应用,内存占用小

52 阅读8分钟

image.png

代码:

from nicegui import ui

def enhanced_drawer_navigation():
    """增强版抽屉导航 - 带活动状态指示"""
    ui.page_title('增强后台')
    
    # 内容容器和状态
    content_container = ui.column().classes('w-full p-6')
    current_page = None
    
    def update_content(content_func, page_name):
        """动态更新内容"""
        nonlocal current_page
        
        # 更新活动状态
        if current_page:
            current_page.classes(remove='bg-blue-50 text-blue-600 border-r-4 border-blue-500')
        
        content_container.clear()
        with content_container:
            content_func()
        
        ui.notify(f'已切换到 {page_name}')
    
    # 头部
    with ui.header().classes('bg-blue-600 text-white shadow-md'):
        with ui.row().classes('w-full justify-between items-center p-4'):
            with ui.row().classes('items-center gap-3'):
                ui.button('', icon='menu', on_click=lambda: left_drawer.toggle()).props('flat color=white')
                ui.icon('dashboard').classes('text-2xl')
                ui.label('增强后台系统').classes('text-xl font-bold')
            
            with ui.row().classes('items-center gap-3'):
                ui.button('', icon='notifications').props('flat color=white')
                ui.avatar('AD', color='primary')
    
    # 左侧抽屉
    with ui.left_drawer().classes('bg-white border-r shadow-lg').props('bordered') as left_drawer:
        with ui.column().classes('w-full'):
            # 用户信息区域
            with ui.column().classes('w-full p-6 bg-gradient-to-r from-blue-500 to-purple-500 text-white'):
                with ui.row().classes('items-center gap-3'):
                    ui.avatar('AD', color='white').classes('ring-2 ring-white')
                    with ui.column():
                        ui.label('管理员').classes('font-semibold')
                        ui.label('admin@system.com').classes('text-blue-100 text-sm')
            
            # 导航菜单
            with ui.column().classes('w-full p-4 gap-1'):
                ui.label('功能菜单').classes('text-lg font-semibold mb-4 text-gray-700')
                
                def create_enhanced_nav(label, content_func, icon_name):
                    # 创建按钮引用,用于后续修改样式
                    button_ref = None
                    
                    def navigate():
                        nonlocal current_page
                        update_content(content_func, label)
                        # 设置活动状态
                        if current_page:
                            current_page.classes(remove='bg-blue-50 text-blue-600 border-r-4 border-blue-500')
                        if button_ref:
                            button_ref.classes(add='bg-blue-50 text-blue-600 border-r-4 border-blue-500')
                            current_page = button_ref
                    
                    with ui.button(label, icon=icon_name, on_click=navigate).props('flat align-left').classes('w-full justify-start py-3 hover:bg-gray-100 rounded-lg transition-colors') as button:
                        button_ref = button
                    
                    return button_ref
                
                # 定义页面内容
                def dashboard_content():
                    ui.label('仪表板概览').classes('text-2xl font-bold mb-6')
                    with ui.grid(columns=3).classes('w-full gap-4'):
                        metrics = [
                            ('总用户', '1,234', 'people', 'blue'),
                            ('销售额', '¥45,678', 'trending_up', 'green'),
                            ('订单数', '456', 'shopping_cart', 'orange'),
                        ]
                        for title, value, icon, color in metrics:
                            with ui.card().classes(f'p-4 border-l-4 border-{color}-500'):
                                with ui.row().classes('items-center justify-between'):
                                    with ui.column():
                                        ui.label(title).classes('text-sm text-gray-600')
                                        ui.label(value).classes('text-2xl font-bold')
                                    ui.icon(icon).classes(f'text-{color}-500 text-2xl')
                
                def users_content():
                    ui.label('用户管理').classes('text-2xl font-bold mb-6')
                    with ui.card().classes('w-full p-4'):
                        with ui.row().classes('w-full justify-between items-center mb-4'):
                            ui.label('用户列表').classes('text-lg font-semibold')
                            ui.button('添加用户', icon='person_add', color='primary')
                        # 用户表格
                        with ui.element('div').classes('h-64 bg-gray-50 rounded border flex items-center justify-center'):
                            ui.label('用户数据表格区域').classes('text-gray-500')
                
                def products_content():
                    ui.label('产品管理').classes('text-2xl font-bold mb-6')
                    with ui.card().classes('w-full p-4'):
                        with ui.row().classes('w-full justify-between items-center mb-4'):
                            ui.label('产品列表').classes('text-lg font-semibold')
                            ui.button('添加产品', icon='add', color='primary')
                        # 产品表格
                        with ui.element('div').classes('h-64 bg-gray-50 rounded border flex items-center justify-center'):
                            ui.label('产品数据表格区域').classes('text-gray-500')
                
                def analytics_content():
                    ui.label('数据分析').classes('text-2xl font-bold mb-6')
                    with ui.grid(columns=2).classes('w-full gap-6'):
                        for i in range(2):
                            with ui.card().classes('p-4'):
                                ui.label(f'图表 {i+1}').classes('text-lg font-semibold mb-4')
                                with ui.element('div').classes('h-48 bg-gray-50 rounded flex items-center justify-center'):
                                    ui.label('图表区域').classes('text-gray-500')
                
                def settings_content():
                    ui.label('系统设置').classes('text-2xl font-bold mb-6')
                    with ui.card().classes('w-full p-4'):
                        with ui.column().classes('gap-4'):
                            ui.label('基本配置').classes('text-lg font-semibold')
                            ui.input(label='系统名称', value='增强后台系统')
                            ui.input(label='公司地址')
                            ui.textarea(label='系统描述')
                            ui.button('保存配置', icon='save', color='primary').classes('w-full')
                
                # 创建导航项
                nav_items = [
                    ('📊 仪表板', dashboard_content, 'dashboard'),
                    ('👥 用户管理', users_content, 'people'),
                    ('📦 产品管理', products_content, 'inventory_2'),
                    ('📈 数据分析', analytics_content, 'analytics'),
                    ('⚙️ 系统设置', settings_content, 'settings'),
                ]
                
                for label, content, icon in nav_items:
                    create_enhanced_nav(label, content, icon)
    
    # 初始内容
    update_content(dashboard_content, '仪表板')

if __name__ in {"__main__", "__mp_main__"}:
    enhanced_drawer_navigation()
    ui.run()

简要说明:

这个程序是一个使用 NiceGUI 框架构建的后台管理系统界面。让我简要说明其主要结构和功能:

程序结构说明

1. 整体布局

  • 头部 (Header): 蓝色导航栏,包含菜单按钮、系统标题和用户信息
  • 左侧抽屉 (Drawer): 可折叠的侧边菜单栏
  • 主内容区: 动态显示不同页面的内容

2. 核心功能

导航系统
# 动态内容切换机制
def update_content(content_func, page_name):
    # 清除旧内容 → 渲染新内容 → 更新活动状态
活动状态管理
  • 当前选中的菜单项会高亮显示(蓝色背景+边框)
  • 切换页面时自动更新活动状态

3. 页面模块

5个主要功能页面:

  1. 📊 仪表板 - 数据显示卡片(用户数、销售额、订单数)
  2. 👥 用户管理 - 用户列表和操作界面
  3. 📦 产品管理 - 产品列表和管理功能
  4. 📈 数据分析 - 图表展示区域
  5. ⚙️ 系统设置 - 系统配置表单

4. 用户体验特性

  • 左侧抽屉保持打开状态,便于快速导航
  • 页面切换时有通知提示
  • 响应式设计,支持移动端
  • 视觉反馈清晰(悬停效果、活动状态)

5. 技术特点

  • 使用 动态内容替换 而非多页面
  • 组件化设计 - 每个页面都是独立函数
  • 状态管理 - 跟踪当前活动页面
  • CSS 类动态操作 - 实现视觉状态切换

运行效果

启动后你会看到:

  1. 蓝色头部导航栏
  2. 左侧打开的抽屉菜单
  3. 默认显示仪表板页面
  4. 点击菜单项切换不同功能页面,左侧菜单保持打开

这是一个**单页面应用(SPA)**风格的后台管理系统模板,适合快速开发企业级管理界面。

第二例:

from nicegui import ui

def enhanced_simple_admin():
    """带活动状态的简单后台"""
    ui.page_title('后台管理系统')
    
    # 页面状态
    current_page = 'dashboard'
    pages = {}
    nav_buttons = {}
    left_drawer = None
    
    def switch_page(page_key, label):
        nonlocal current_page
        print(f"切换页面: {current_page} -> {page_key}")
        
        # 隐藏当前页面
        if current_page in pages:
            pages[current_page].style('display: none')
            print(f"隐藏页面: {current_page}")
        
        # 移除当前按钮的活动状态
        if current_page in nav_buttons:
            nav_buttons[current_page].classes(remove='bg-blue-100 text-blue-600')
            print(f"移除活动状态: {current_page}")
        
        # 显示新页面
        if page_key in pages:
            pages[page_key].style('display: flex')  # 使用 flex 显示
            print(f"显示页面: {page_key}")
        else:
            print(f"错误: 页面 {page_key} 不存在!")
        
        # 设置新按钮的活动状态
        if page_key in nav_buttons:
            nav_buttons[page_key].classes(add='bg-blue-100 text-blue-600')
            print(f"设置活动状态: {page_key}")
        
        current_page = page_key
        # ui.notify(f'切换到 {label}')
    
    # 头部
    with ui.header().classes('bg-blue-600 text-white'):
        with ui.row().classes('w-full justify-between items-center p-4'):
            with ui.row().classes('items-center gap-3'):
                menu_btn = ui.button('', icon='menu').props('flat color=white')
                ui.label('后台管理系统').classes('text-xl font-bold')
            
            with ui.row().classes('items-center gap-3'):
                ui.button('', icon='notifications').props('flat color=white')
                ui.avatar('AD', color='primary')
    
    # 左侧抽屉
    with ui.left_drawer().classes('bg-white border-r').props('bordered') as drawer:
        left_drawer = drawer
        with ui.column().classes('w-full p-4 gap-1'):
            ui.label('导航菜单').classes('text-lg font-semibold mb-4 text-gray-700')
            
            # 创建导航按钮
            nav_configs = [
                ('dashboard', '📊 仪表板', 'dashboard'),
                ('users', '👥 用户管理', 'people'),
                ('products', '📦 产品管理', 'inventory_2'),
                ('analytics', '📈 数据分析', 'analytics'),
                ('settings', '⚙️ 系统设置', 'settings'),
            ]
            
            for page_key, label, icon in nav_configs:
                btn = ui.button(label, icon=icon, 
                              on_click=lambda _, pk=page_key, lb=label: switch_page(pk, lb))\
                    .props('flat align-left')\
                    .classes('w-full justify-start py-3 hover:bg-gray-100 rounded-lg')
                nav_buttons[page_key] = btn
    
    # 绑定菜单按钮
    menu_btn.on('click', lambda: left_drawer.toggle())
    
    # 主内容区域
    with ui.column().classes('w-full p-6'):
        # 仪表板
        with ui.column().classes('w-full') as dashboard_page:
            pages['dashboard'] = dashboard_page
            ui.label('仪表板概览').classes('text-2xl font-bold mb-6')
            with ui.grid(columns=3).classes('w-full gap-4'):
                metrics = [
                    ('总用户', '1,234', 'people', 'blue'),
                    ('销售额', '¥45,678', 'trending_up', 'green'),
                    ('订单数', '456', 'shopping_cart', 'orange'),
                ]
                for title, value, icon, color in metrics:
                    with ui.card().classes(f'p-4 border-l-4 border-{color}-500'):
                        with ui.row().classes('items-center justify-between'):
                            with ui.column():
                                ui.label(title).classes('text-sm text-gray-600')
                                ui.label(value).classes('text-2xl font-bold')
                            ui.icon(icon).classes(f'text-{color}-500 text-2xl')
        
        # 用户管理
        with ui.column().classes('w-full') as users_page:
            pages['users'] = users_page
            users_page.style('display: none')
            ui.label('用户管理').classes('text-2xl font-bold mb-6')
            with ui.card().classes('w-full p-4'):
                with ui.row().classes('w-full justify-between items-center mb-4'):
                    ui.label('用户列表').classes('text-lg font-semibold')
                    ui.button('添加用户', icon='person_add', color='primary')
                with ui.element('div').classes('h-48 bg-gray-100 rounded flex items-center justify-center'):
                    ui.label('用户表格区域').classes('text-gray-500')
        
        # 产品管理
        with ui.column().classes('w-full') as products_page:
            pages['products'] = products_page
            products_page.style('display: none')
            ui.label('产品管理').classes('text-2xl font-bold mb-6')
            with ui.card().classes('w-full p-4'):
                with ui.row().classes('w-full justify-between items-center mb-4'):
                    ui.label('产品列表').classes('text-lg font-semibold')
                    ui.button('添加产品', icon='add', color='primary')
                with ui.element('div').classes('h-48 bg-gray-100 rounded flex items-center justify-center'):
                    ui.label('产品表格区域').classes('text-gray-500')
        
        # 数据分析
        with ui.column().classes('w-full') as analytics_page:
            pages['analytics'] = analytics_page
            analytics_page.style('display: none')
            ui.label('数据分析').classes('text-2xl font-bold mb-6')
            with ui.grid(columns=2).classes('w-full gap-6'):
                for i in range(2):
                    with ui.card().classes('p-4'):
                        ui.label(f'图表 {i+1}').classes('text-lg font-semibold mb-4')
                        with ui.element('div').classes('h-48 bg-gray-100 rounded flex items-center justify-center'):
                            ui.label('图表区域').classes('text-gray-500')
        
        # 系统设置
        with ui.column().classes('w-full') as settings_page:
            pages['settings'] = settings_page
            settings_page.style('display: none')
            ui.label('系统设置').classes('text-2xl font-bold mb-6')
            with ui.card().classes('w-full p-4'):
                with ui.column().classes('gap-4'):
                    ui.label('基本设置').classes('text-lg font-semibold')
                    ui.input(label='系统名称', value='后台管理系统')
                    ui.input(label='管理员邮箱')
                    ui.button('保存设置', icon='save', color='primary')
    
    # 设置默认活动状态
    # print("初始化完成,当前页面:", current_page)
    nav_buttons['dashboard'].classes(add='bg-blue-100 text-blue-600')

if __name__ in {"__main__", "__mp_main__"}:
    enhanced_simple_admin()
    ui.run()