前言
NiceGUI 是一款用 Python 写前端界面、快速开发交互式网页应用的轻量级框架。它结合了简洁的代码风格和现代化的 UI 组件,让你无缝打造漂亮网页。本篇就带你大概了解下这个神奇的python前端框架,看看是不是你的菜。
NiceGUI 简介
-
纯 Python 编写,免写 HTML/CSS/JS
-
基于 FastAPI,支持异步和高性能
-
丰富组件库:按钮、输入框、图表、弹窗等
-
适合快速开发工具、仪表盘、管理后台
安装与启动
pip install nicegui
最简示例:
from nicegui import ui
ui.label('你好,NiceGUI!')
ui.run()
核心组件使用示例
-
ui.button
按钮事件绑定 -
ui.input
文本输入框 -
ui.slider
滑块 -
ui.chart
图表展示 -
弹窗、通知、布局组件等
示例:
from nicegui import ui
import random
import time
def show_message(message, sender):
ui.notify(f'{sender.text} 被点击!消息内容:{message}')
# 按钮组件(已适配新版本)
ui.button('基础按钮', on_click=lambda: show_message('普通按钮', ui.button))
ui.button('🚀 表情按钮', on_click=lambda e: ui.notify(f'触发事件:{e.name}'))
# 输入框组件(已适配新版本)
name_input = ui.input(label='你的名字', value='匿名用户').props('outlined')
ui.button('显示问候', on_click=lambda: ui.notify(f'你好,{name_input.value}!'))
# 修正后的滑块组件(2.20.0版本语法)
slider_value = ui.label('当前值:50').classes('text-h5')
def update_slider(value):
slider_value.set_text(f'当前值:{int(value)}')
# 新版本要求必须使用关键字参数
ui.slider(
value=50,
min=0,
max=100,
on_change=update_slider
).props('label-always')
# 图表组件(已适配新版本)
chart_data = [{'x': i, 'y': random.randint(0, 100)} for i in range(10)]
chart = ui.echart([{'name': '随机数据', 'values': chart_data}]).props('line')
def update_chart():
while True:
chart_data.append({'x': len(chart_data), 'y': random.randint(0, 100)})
if len(chart_data) > 20:
chart_data.pop(0)
chart.update([{'name': '随机数据', 'values': chart_data}])
time.sleep(1)
# 修正后的对话框组件(2.20.0版本)
advanced_dialog = ui.dialog()
with advanced_dialog:
ui.label('对话框内容可以包含任意组件').classes('text-h5 q-mb-md')
ui.button('确认', on_click=lambda: advanced_dialog.close())
ui.button('取消', on_click=lambda: advanced_dialog.close())
ui.notify('任务进行中...')
with ui.row().classes('items-center q-gutter-md'):
ui.button('水平排列按钮1')
ui.button('水平排列按钮2')
with ui.column().classes('items-start q-gutter-y-sm'):
ui.input(label='垂直排列输入框1')
ui.input(label='垂直排列输入框2')
ui.color_picker(on_pick='#FF0000')
# 启动界面
ui.run(title='NiceGUI 2.20.0 组件演示', favicon='🛠️')
布局和页面结构
用nicegui实现的一个布局和页面结构演示系统。基础环境配置:
Python 3.10.11
conda 25.5.1
nicegui==2.20.0
from nicegui import ui
# 设置全局样式
ui.query('html').classes('h-full')
ui.query('body').classes('h-full m-0 overflow-hidden')
ui.add_body_html('<style>#__nuxt { height: 100%; }</style>')
# 创建顶部导航栏 - 必须是顶级元素
header = ui.header().classes(
'bg-blue-600 text-white shadow-lg p-4 flex items-center justify-between fixed top-0 left-0 right-0 z-50')
with header:
ui.label("企业管理系统").classes("text-2xl font-bold")
with ui.row().classes("gap-4"):
ui.button("首页", icon="home")
ui.button("通知", icon="notifications", color="yellow-500")
ui.button("设置", icon="settings", color="gray-500")
with ui.button(icon="person"):
ui.label("管理员")
# 创建侧边栏 - 必须是顶级元素
sidebar = ui.left_drawer(value=True, fixed=False, bordered=True) \
.classes('bg-white shadow-lg mt-14') \
.props('width=250 breakpoint=500') \
.classes('lt-md:hidden')
with sidebar:
ui.label("导航菜单").classes("text-xl font-bold p-4 border-b")
with ui.column().classes("p-2 gap-1"):
ui.button("仪表盘", icon="dashboard").props("flat").classes("justify-start")
ui.button("用户管理", icon="people").props("flat").classes("justify-start")
ui.button("订单系统", icon="shopping_cart").props("flat").classes("justify-start")
ui.button("财务统计", icon="bar_chart").props("flat").classes("justify-start")
ui.button("系统设置", icon="settings").props("flat").classes("justify-start")
with ui.column().classes("absolute bottom-0 left-0 w-full p-4 border-t"):
ui.button("退出系统", icon="logout", color="red").props("flat").classes("w-full")
# 创建主内容区域容器
main_content = ui.column().classes('pt-14 pb-10 h-full overflow-auto')
with main_content:
# 标签页组件
with ui.tabs().classes('w-full bg-white rounded-lg shadow mb-4') as tabs:
dashboard = ui.tab('仪表盘', icon='dashboard')
users = ui.tab('用户管理', icon='people')
orders = ui.tab('订单系统', icon='shopping_cart')
reports = ui.tab('分析报表', icon='analytics')
# 标签页内容面板
with ui.tab_panels(tabs, value=dashboard).classes('w-full bg-white rounded-lg shadow p-4'):
# 仪表盘标签页内容
with ui.tab_panel(dashboard):
ui.label("系统概览").classes("text-2xl mb-4")
# 响应式卡片布局
with ui.grid(columns=4).classes('w-full gap-4 md:grid-cols-2 lg:grid-cols-4'):
with ui.card().classes('bg-blue-50'):
ui.label("用户总数").classes("text-gray-500")
ui.label("1,248").classes("text-3xl font-bold")
ui.linear_progress(0.65).props("instant-feedback")
with ui.card().classes('bg-green-50'):
ui.label("本月订单").classes("text-gray-500")
ui.label("342").classes("text-3xl font-bold")
ui.linear_progress(0.82, color='green')
with ui.card().classes('bg-yellow-50'):
ui.label("待处理").classes("text-gray-500")
ui.label("12").classes("text-3xl font-bold")
ui.linear_progress(0.15, color='orange')
with ui.card().classes('bg-purple-50'):
ui.label("营收总额").classes("text-gray-500")
ui.label("¥89,200").classes("text-3xl font-bold")
ui.linear_progress(0.92, color='purple')
# 图表区域
with ui.row().classes('w-full mt-4 gap-4 flex-col lg:flex-row'):
with ui.card().classes('flex-1 p-4'):
ui.label("用户增长趋势").classes("text-xl mb-2")
ui.echart({
'xAxis': {'type': 'category', 'data': ['1月', '2月', '3月', '4月', '5月']},
'yAxis': {'type': 'value'},
'series': [{'data': [120, 200, 150, 80, 70], 'type': 'line'}]
}).classes('w-full h-64')
with ui.card().classes('flex-1 p-4'):
ui.label("订单分布").classes("text-xl mb-2")
ui.echart({
'tooltip': {'trigger': 'item'},
'series': [{
'name': '订单类型',
'type': 'pie',
'radius': '50%',
'data': [
{'value': 1048, 'name': '线上支付'},
{'value': 735, 'name': '货到付款'},
{'value': 580, 'name': '对公转账'},
{'value': 484, 'name': '其他'}
]
}]
}).classes('w-full h-64')
# 用户管理标签页内容
with ui.tab_panel(users):
ui.label("用户管理").classes("text-2xl mb-4")
# 搜索和操作区域
with ui.row().classes('w-full items-center gap-4 mb-4'):
ui.input(placeholder="搜索用户...").props("outlined dense").classes("flex-1")
ui.button("添加用户", icon="add", color="primary")
ui.button("导出数据", icon="download")
# 用户表格
columns = [
{'name': 'id', 'label': 'ID', 'field': 'id'},
{'name': 'name', 'label': '姓名', 'field': 'name'},
{'name': 'email', 'label': '邮箱', 'field': 'email'},
{'name': 'role', 'label': '角色', 'field': 'role'},
{'name': 'status', 'label': '状态', 'field': 'status'},
]
rows = [
{'id': 1, 'name': '张三', 'email': 'zhangsan@example.com', 'role': '管理员', 'status': '激活'},
{'id': 2, 'name': '李四', 'email': 'lisi@example.com', 'role': '编辑', 'status': '激活'},
{'id': 3, 'name': '王五', 'email': 'wangwu@example.com', 'role': '查看', 'status': '禁用'},
{'id': 4, 'name': '赵六', 'email': 'zhaoliu@example.com', 'role': '财务', 'status': '激活'},
]
ui.table(columns=columns, rows=rows, row_key='id').classes('w-full')
# 其他标签页内容
with ui.tab_panel(orders):
ui.label("订单管理").classes("text-2xl mb-4")
ui.markdown("这里是订单管理内容...")
with ui.tab_panel(reports):
ui.label("分析报表").classes("text-2xl mb-4")
ui.markdown("这里是数据分析报表...")
# 创建底部状态栏 - 必须是顶级元素
footer = ui.footer().classes(
'bg-gray-800 text-white p-2 flex justify-between items-center fixed bottom-0 left-0 right-0 z-50')
with footer:
ui.label("© 2023 企业管理系统 - 版权所有")
ui.label("系统状态: 运行中").classes('text-green-400')
# 添加移动端侧边栏切换按钮 - 必须是顶级元素
toggle_button = ui.button(icon="menu", color="primary") \
.classes('fixed bottom-4 right-4 shadow-lg md:hidden z-50')
def toggle_sidebar():
sidebar.value = not sidebar.value
toggle_button.on('click', toggle_sidebar)
ui.run(title="企业管理系统", port=8080, reload=False)
部署建议
-
本地启动
python app.py
-
使用 uvicorn/gunicorn 部署
采用uvicorn
pip install uvicorn
uvicorn app:app --host 0.0.0.0 --port 8080
采用gunicorn
pip install gunicorn uvicorn[standard]
gunicorn -k uvicorn.workers.UvicornWorker main:app --bind 0.0.0.0:8080
总结
优点 | 局限 |
---|---|
纯 Python,无需前端经验 | 生态相对年轻,组件有限 |
快速开发漂亮界面 | 高级交互需更复杂代码 |
支持异步和多用户 | 不适合大型复杂系统 |
一句话总结:NiceGUI 让 Python 开发者轻松打造现代化网页应用,入门简单,体验极佳!