python-webui
Python + Vue 3 实时数据可视化演示项目,探索 WebSocket 双向通信与全局变量实时渲染方案。
PythonVue 3WebSocketasyncioElement Plus
项目简介
python-webui 是一个探索 Python 后端与 Vue 前端实时通信方案的演示项目。项目实现了 Python 全局变量的实时渲染和日志的实时推送,通过 WebSocket 双向通信机制,将后端数据变化毫秒级同步到前端界面。项目采用前后端分离架构,适合学习 Python-Vue 集成和异步编程模式。
主要特性
- ⚡ 实时数据同步:WebSocket 实现毫秒级数据推送
- 📊 多类型数据展示:支持 JSON、文本、数字、图片四种数据类型
- 📝 实时日志面板:Python 日志实时推送到前端,支持颜色区分
- 🔄 自动重连机制:断线后自动尝试重新连接
- 🚀 异步并发架构:多任务并发运行,充分利用 asyncio
技术栈
| 类别 | 技术 |
|---|---|
| 后端语言 | Python 3.x |
| WebSocket | websockets 库 |
| 异步框架 | asyncio |
| 前端框架 | Vue 3 |
| 构建工具 | Vite |
| UI 组件库 | Element Plus |
| 通信协议 | WebSocket |
技术亮点
亮点一:自定义 Logging Handler + asyncio.Queue 桥梁
将 Python 标准日志系统与 WebSocket 无缝集成:
class WebSocketLogHandler(logging.Handler):
def emit(self, record):
msg = self.format(record)
log_entry = {
"message": msg,
"level": record.levelname,
"timestamp": datetime.fromtimestamp(record.created).isoformat(),
}
log_queue.put_nowait(log_entry) # 放入异步队列
设计优势:
- 解耦日志产生和日志推送
- 利用
asyncio.Queue实现线程安全的数据传递 - 日志系统无需关心 WebSocket 实现
亮点二:图片 Base64 预编码优化
启动时一次性编码,避免运行时重复计算:
# 启动时预编码
for img_path in sorted(imgs_dir.iterdir()):
raw = img_path.read_bytes()
b64 = base64.b64encode(raw).decode("ascii")
image_list.append({"filename": img_path.name, "base64": b64})
亮点三:Vue Composition API 最佳实践
使用 Composable 模式封装 WebSocket 逻辑:
export function useWebSocket(url = 'ws://localhost:8765') {
const jsonData = ref(null)
const logs = ref([])
onMounted(() => connect())
onUnmounted(() => disconnect())
return { jsonData, logs, connected, ... }
}
优势:
- 逻辑复用性强
- 生命周期管理清晰
- 响应式状态自动更新 UI
亮点四:多任务并发架构
使用 asyncio.gather 并发运行多个独立任务:
| 任务 | 职责 | 频率 |
|---|---|---|
start_server | WebSocket 服务器 | 持续运行 |
data_selector_task | 更新全局变量 | 1-2秒随机 |
ws_broadcaster_task | 推送数据 | 每1秒 |
log_pusher_task | 推送日志 | 实时 |
self_talking_task | 模拟日志 | 0.1-1秒随机 |
亮点五:前端自动重连机制
断线后自动尝试重新连接:
ws.onclose = () => {
connected.value = false;
reconnectTimer = setTimeout(connect, 2000);
};
亮点六:日志面板自动滚动
新日志到达时自动滚动到底部:
watch(
logs,
async () => {
await nextTick();
if (logContainer.value) {
logContainer.value.scrollTop = logContainer.value.scrollHeight;
}
},
{ deep: true },
);
相关链接
- 代码仓库:GitHub