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. 部署方案

平台命令
Herokuheroku create && git push heroku main
Railwayrailway deploy
Vercelvercel --prod
Dockerdocker 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 仓库用户认证数据库集成,或 移动端优化 吗?随时说!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注