Dash 多页面布局
Dash 多页面布局完整指南
Dash 多页面应用(Multi-Page App) 使用 dcc.Location + dcc.Link + 文件夹结构,实现类似传统 Web 应用的导航体验。完美适用于 DASH 加密货币仪表板:首页(概览)、钱包、交易、图表、设置等。
核心架构
dash-app/
├── assets/
│ └── style.css # 全局样式
├── pages/
│ ├── __init__.py # 页面注册
│ ├── home.py # 首页
│ ├── wallet.py # 钱包
│ ├── charts.py # 图表
│ └── masternodes.py # 主节点
├── app.py # 主应用
└── requirements.txt
1. 主应用文件 app.py
import dash
from dash import html, dcc
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc
from pages import home, wallet, charts, masternodes
# 初始化应用(使用 Bootstrap 主题)
app = dash.Dash(__name__,
external_stylesheets=[dbc.themes.BOOTSTRAP],
suppress_callback_exceptions=True)
# 应用布局
app.layout = html.Div([
dcc.Location(id='url', refresh=False),
html.Div(id='page-content')
])
# 路由回调:根据 URL 加载页面
@app.callback(Output('page-content', 'children'),
Input('url', 'pathname'))
def display_page(pathname):
if pathname == '/wallet/':
return wallet.layout
elif pathname == '/charts/':
return charts.layout
elif pathname == '/masternodes/':
return masternodes.layout
else:
return home.layout
if __name__ == '__main__':
app.run_server(debug=True, port=8050)
2. 公共导航栏组件 components/navbar.py
import dash_bootstrap_components as dbc
from dash import html, dcc
navbar = dbc.NavbarSimple(
children=[
html.Div([
html.Img(src="assets/dash-logo.png", height="30px"),
html.Span("Dash Dashboard", className="ms-2")
], className="d-flex align-items-center"),
dbc.Nav([
dbc.NavLink("首页", href="/", active="exact"),
dbc.NavLink("钱包", href="/wallet/", active="exact"),
dbc.NavLink("图表", href="/charts/", active="exact"),
dbc.NavLink("主节点", href="/masternodes/", active="exact"),
], pills=True, className="ms-auto")
],
brand_href="/",
color="primary",
dark=True,
className="mb-4"
)
3. 页面 1:首页 pages/home.py
import dash
from dash import html, dcc
from components.navbar import navbar
import plotly.express as px
import pandas as pd
layout = html.Div([
navbar,
# 英雄区域
dbc.Container([
dbc.Row([
dbc.Col([
html.H1("Dash 实时监控中心", className="display-4"),
html.P("价格 • 交易 • 主节点 • 钱包",
className="lead text-muted")
], width=8)
], className="text-center text-md-start mb-5")
], fluid=True),
# 关键指标卡片
dbc.Container([
dbc.Row([
dbc.Col([
dbc.Card([
dbc.CardBody([
html.H4(id="price-card", children="加载中...", className="card-title"),
html.P("当前价格", className="card-text")
])
], color="primary", inverse=True)
], width=3),
dbc.Col([
dbc.Card([
dbc.CardBody([
html.H4(id="volume-card", children="0", className="card-title"),
html.P("24h 交易量", className="card-text")
])
], color="success", inverse=True)
], width=3),
dbc.Col([
dbc.Card([
dbc.CardBody([
html.H4(id="mn-count", children="加载中...", className="card-title"),
html.P("主节点数量", className="card-text")
])
], color="info", inverse=True)
], width=3),
dbc.Col([
dbc.Card([
dbc.CardBody([
html.H4(id="balance-card", children="0.00 DASH", className="card-title"),
html.P("钱包余额", className="card-text")
])
], color="warning", inverse=True)
], width=3),
], className="g-4 mb-5")
]),
# 快速操作
dbc.Container([
html.H3("快速操作"),
dbc.Row([
dbc.Col([
dbc.Button("查看钱包", href="/wallet/", color="primary", size="lg", className="w-100")
], width=3),
dbc.Col([
dbc.Button("实时图表", href="/charts/", color="success", size="lg", className="w-100")
], width=3),
dbc.Col([
dbc.Button("主节点统计", href="/masternodes/", color="info", size="lg", className="w-100")
], width=3)
])
])
])
4. 页面 2:钱包页面 pages/wallet.py
import dash
from dash import html, dcc
from components.navbar import navbar
import dash_bootstrap_components as dbc
layout = html.Div([
navbar,
dbc.Container([
html.H2("钱包管理"),
# 余额卡片
dbc.Row([
dbc.Col([
dbc.Card([
dbc.CardBody([
html.H3(id="wallet-balance", children="0.0000 DASH",
className="text-primary mb-0"),
html.P("总余额", className="mb-0 text-muted")
], className="text-center")
], className="shadow h-100")
], width=4),
dbc.Col([
dbc.Card([
dbc.CardBody([
html.H4(id="wallet-address", children="yP...", className="mb-2"),
dbc.Button("复制地址", id="copy-btn", color="link", className="p-0")
], className="text-center")
], className="shadow h-100")
], width=4),
dbc.Col([
dbc.Card([
dbc.CardBody([
html.H5("快速发送", className="mb-3"),
dbc.InputGroup([
dbc.Input(id="send-amount", placeholder="金额", type="number"),
dbc.Button("发送", id="send-btn", color="primary")
])
])
], className="shadow h-100")
], width=4)
], className="mb-5 g-4"),
# 交易历史
html.H4("最近交易"),
dbc.Table.from_dataframe(id="tx-table", striped=True, bordered=True, hover=True)
])
])
5. 页面 3:图表页面 pages/charts.py
import dash
from dash import html, dcc
from components.navbar import navbar
import plotly.graph_objects as go
import plotly.express as px
layout = html.Div([
navbar,
dbc.Container([
html.H2("实时图表"),
# 时间范围选择
dbc.Row([
dbc.Col([
dcc.Dropdown(
id='time-range',
options=[
{'label': '1小时', 'value': '1h'},
{'label': '24小时', 'value': '24h'},
{'label': '7天', 'value': '7d'}
],
value='24h'
)
], width=4)
], className="mb-4"),
# 多图布局
dbc.Row([
dbc.Col(dcc.Graph(id='price-chart'), width=8),
dbc.Col([
dcc.Graph(id='volume-gauge'),
dcc.Graph(id='ma-chart')
], width=4)
], className="g-4"),
# 实时更新
dcc.Interval(id='charts-interval', interval=5*1000, n_intervals=0)
])
])
6. 页面 4:主节点页面 pages/masternodes.py
import dash
from dash import html
from components.navbar import navbar
import dash_bootstrap_components as dbc
layout = html.Div([
navbar,
dbc.Container([
html.H2("主节点统计"),
dbc.Row([
dbc.Col([
dbc.Card([
dbc.CardHeader("主节点分布"),
dbc.CardBody([
dcc.Graph(id='mn-pie-chart')
])
])
], width=6),
dbc.Col([
dbc.Card([
dbc.CardHeader("ROI 计算器"),
dbc.CardBody([
dbc.Input(id="investment", placeholder="投资金额", type="number"),
html.Br(),
dbc.Button("计算", id="calc-btn"),
html.H4(id="roi-result", children="0%")
])
])
], width=6)
])
])
])
7. 页面注册 pages/__init__.py
from . import home, wallet, charts, masternodes
__all__ = ["home", "wallet", "charts", "masternodes"]
8. 全局样式 assets/style.css
.dash-logo {
border-radius: 50%;
}
.card {
transition: transform 0.2s;
}
.card:hover {
transform: translateY(-5px);
}
.navbar-brand {
font-weight: bold;
}
9. 完整 requirements.txt
dash==2.17.0
plotly==5.18.0
dash-bootstrap-components==1.6.0
pandas==2.1.4
requests==2.31.0
10. 一键启动脚本 run.py
import subprocess
import sys
import os
def install_requirements():
subprocess.check_call([sys.executable, "-m", "pip", "install", "-r", "requirements.txt"])
if __name__ == "__main__":
install_requirements()
os.system("python app.py")
运行:
python run.py
# 访问 http://127.0.0.1:8050/
11. 高级特性
添加回调(app.py 末尾)
# 全局回调:更新首页卡片
@app.callback(
[Output('price-card', 'children'),
Output('volume-card', 'children'),
Output('mn-count', 'children')],
[Input('home-interval', 'n_intervals')]
)
def update_home_cards(n):
# 模拟数据更新
price = 28.50
volume = "1.2M"
mn_count = "3,850"
return f"${price:.2f}", volume, f"{mn_count:,}"
# 钱包页面回调
@app.callback(
Output('wallet-balance', 'children'),
Input('wallet-interval', 'n_intervals')
)
def update_wallet(n):
return "2.8473 DASH"
12. 部署方案
| 平台 | 命令 |
|---|---|
| Heroku | heroku create && git push heroku main |
| Railway | railway deploy |
| Vercel | vercel --prod |
| Docker | docker build -t dash-app . && docker run -p 8050:8050 dash-app |
Dockerfile:
FROM python:3.11-slim
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
EXPOSE 8050
CMD ["python", "app.py"]
效果预览
首页 → 关键指标卡片 + 快速操作按钮
钱包 → 余额/地址/发送/交易历史
图表 → 实时价格K线 + 交易量 + MA
主节点 → 分布饼图 + ROI计算器
导航:顶部导航栏 + 面包屑 + 侧边栏(可选)
一句话总结:使用 文件夹结构 + dcc.Location + 回调路由,5 分钟构建专业多页面 DASH 仪表板,支持实时数据、响应式设计、一键部署。
需要我提供 完整 GitHub 仓库、用户认证、数据库集成,或 移动端优化 吗?随时说!