dcc.Tabs#

参考:tabs

dcc.Tabsdcc.Tab 组件可以用来在应用中创建选项卡式区域。dcc.Tab 组件控制单个选项卡的样式和值,而 dcc.Tabs 组件则包含一组 dcc.Tab 组件。

方法 1. 内容作为回调#

将回调附加到 Tabs 的 value 属性,并在回调中更新容器的 children 属性。

from dash import Dash, dcc, html, Input, Output, callback

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = Dash(__name__, external_stylesheets=external_stylesheets)

app.layout = html.Div([
    html.H1('Dash Tabs component demo'),
    dcc.Tabs(id="tabs-example-graph", value='tab-1-example-graph', children=[
        dcc.Tab(label='Tab One', value='tab-1-example-graph'),
        dcc.Tab(label='Tab Two', value='tab-2-example-graph'),
    ]),
    html.Div(id='tabs-content-example-graph')
])

@callback(Output('tabs-content-example-graph', 'children'),
          Input('tabs-example-graph', 'value'))
def render_content(tab):
    if tab == 'tab-1-example-graph':
        return html.Div([
            html.H3('Tab content 1'),
            dcc.Graph(
                figure={
                    'data': [{
                        'x': [1, 2, 3],
                        'y': [3, 1, 2],
                        'type': 'bar'
                    }]
                }
            )
        ])
    elif tab == 'tab-2-example-graph':
        return html.Div([
            html.H3('Tab content 2'),
            dcc.Graph(
                id='graph-2-tabs-dcc',
                figure={
                    'data': [{
                        'x': [1, 2, 3],
                        'y': [5, 10, 6],
                        'type': 'bar'
                    }]
                }
            )
        ])

# if __name__ == '__main__':
#     app.run(debug=True)

方法 2. 内容作为选项卡子项#

除了通过回调显示内容外,您还可以将内容直接嵌入到 Tab 组件的 children 属性中:

from dash import Dash, dcc, html

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = Dash(__name__, external_stylesheets=external_stylesheets)

app.layout = html.Div([
    dcc.Tabs([
        dcc.Tab(label='Tab one', children=[
            dcc.Graph(
                figure={
                    'data': [
                        {'x': [1, 2, 3], 'y': [4, 1, 2],
                            'type': 'bar', 'name': 'SF'},
                        {'x': [1, 2, 3], 'y': [2, 4, 5],
                         'type': 'bar', 'name': 'Montréal'},
                    ]
                }
            )
        ]),
        dcc.Tab(label='Tab two', children=[
            dcc.Graph(
                figure={
                    'data': [
                        {'x': [1, 2, 3], 'y': [1, 4, 1],
                            'type': 'bar', 'name': 'SF'},
                        {'x': [1, 2, 3], 'y': [1, 2, 3],
                         'type': 'bar', 'name': 'Montréal'},
                    ]
                }
            )
        ]),
        dcc.Tab(label='Tab three', children=[
            dcc.Graph(
                figure={
                    'data': [
                        {'x': [1, 2, 3], 'y': [2, 4, 3],
                            'type': 'bar', 'name': 'SF'},
                        {'x': [1, 2, 3], 'y': [5, 4, 3],
                         'type': 'bar', 'name': 'Montréal'},
                    ]
                }
            )
        ]),
    ])
])

# if __name__ == '__main__':
#     app.run(debug=True)

小技巧

请注意,这种方法有一个缺点:它要求您预先计算每个选项卡的 children 属性,并一次性通过网络发送所有选项卡的内容。回调方法允许您在需要时(即点击选项卡时)动态计算选项卡的内容。

样式化选项卡组件#

使用 CSS 类#

通过为 className 属性提供自定义的 CSS 类,可以使用 CSS 类来样式化 Tabs(和 Tab)组件:

from dash import Dash, dcc, html, Input, Output, callback

app = Dash(__name__)

app.layout = html.Div([
    dcc.Tabs(
        id="tabs-with-classes",
        value='tab-2',
        parent_className='custom-tabs',
        className='custom-tabs-container',
        children=[
            dcc.Tab(
                label='Tab one',
                value='tab-1',
                className='custom-tab',
                selected_className='custom-tab--selected'
            ),
            dcc.Tab(
                label='Tab two',
                value='tab-2',
                className='custom-tab',
                selected_className='custom-tab--selected'
            ),
            dcc.Tab(
                label='Tab three, multiline',
                value='tab-3', className='custom-tab',
                selected_className='custom-tab--selected'
            ),
            dcc.Tab(
                label='Tab four',
                value='tab-4',
                className='custom-tab',
                selected_className='custom-tab--selected'
            ),
        ]),
    html.Div(id='tabs-content-classes')
])

@callback(Output('tabs-content-classes', 'children'),
              Input('tabs-with-classes', 'value'))
def render_content(tab):
    if tab == 'tab-1':
        return html.Div([
            html.H3('Tab content 1')
        ])
    elif tab == 'tab-2':
        return html.Div([
            html.H3('Tab content 2')
        ])
    elif tab == 'tab-3':
        return html.Div([
            html.H3('Tab content 3')
        ])
    elif tab == 'tab-4':
        return html.Div([
            html.H3('Tab content 4')
        ])

# if __name__ == '__main__':
#     app.run(debug=True)

请注意,通过为 parent_className 属性提供一个类,我们也可以对 Tabs 的容器进行样式化,这里我们使用它来在下方绘制边框,将实际的 Tabs(带内边距)更居中地定位。我们还为常规的 Tab 组件添加了 display: flexjustify-content: center,以便多行标签不会破坏文本的流动。相应的 CSS 文件(assets/tabs.css)如下所示。将该文件保存在 assets/ 文件夹中(可以根据您的需要命名)。Dash 会在加载应用时自动包含此 CSS。

.custom-tabs-container {
    width: 85%;
}
.custom-tabs {
    border-top-left-radius: 3px;
    background-color: #f9f9f9;
    padding: 0px 24px;
    border-bottom: 1px solid #d6d6d6;
}

.custom-tab {
    color:#586069;
    border-top-left-radius: 3px;
    border-top-right-radius: 3px;
    border-top: 3px solid transparent !important;
    border-left: 0px !important;
    border-right: 0px !important;
    border-bottom: 0px !important;
    background-color: #fafbfc;
    padding: 12px !important;
    font-family: "system-ui";
    display: flex !important;
    align-items: center;
    justify-content: center;
}
.custom-tab--selected {
    color: black;
    box-shadow: 1px 1px 0px white;
    border-left: 1px solid lightgrey !important;
    border-right: 1px solid lightgrey !important;
    border-top: 3px solid #e36209 !important;
}

使用内联样式#

提供 CSS 类的一种替代方法是直接提供样式字典:

from dash import Dash, dcc, html, Input, Output, callback

app = Dash(__name__)

tabs_styles = {
    'height': '44px'
}
tab_style = {
    'borderBottom': '1px solid #d6d6d6',
    'padding': '6px',
    'fontWeight': 'bold'
}

tab_selected_style = {
    'borderTop': '1px solid #d6d6d6',
    'borderBottom': '1px solid #d6d6d6',
    'backgroundColor': '#119DFF',
    'color': 'white',
    'padding': '6px'
}

app.layout = html.Div([
    dcc.Tabs(id="tabs-styled-with-inline", value='tab-1', children=[
        dcc.Tab(label='Tab 1', value='tab-1', style=tab_style, selected_style=tab_selected_style),
        dcc.Tab(label='Tab 2', value='tab-2', style=tab_style, selected_style=tab_selected_style),
        dcc.Tab(label='Tab 3', value='tab-3', style=tab_style, selected_style=tab_selected_style),
        dcc.Tab(label='Tab 4', value='tab-4', style=tab_style, selected_style=tab_selected_style),
    ], style=tabs_styles),
    html.Div(id='tabs-content-inline')
])

@callback(Output('tabs-content-inline', 'children'),
              Input('tabs-styled-with-inline', 'value'))
def render_content(tab):
    if tab == 'tab-1':
        return html.Div([
            html.H3('Tab content 1')
        ])
    elif tab == 'tab-2':
        return html.Div([
            html.H3('Tab content 2')
        ])
    elif tab == 'tab-3':
        return html.Div([
            html.H3('Tab content 3')
        ])
    elif tab == 'tab-4':
        return html.Div([
            html.H3('Tab content 4')
        ])

# if __name__ == '__main__':
#     app.run(debug=True)

最后,您可以通过在字典中指定 "border"(边框)、"primary"(主要)和 "background"(背景)颜色来设置 Tabs 组件的颜色属性。如果您要使用它们,请确保都设置了!

from dash import Dash, dcc, html, Input, Output, callback

app = Dash(__name__)

app.layout = html.Div([
    dcc.Tabs(id="tabs-styled-with-props", value='tab-1', children=[
        dcc.Tab(label='1', value='tab-1'),
        dcc.Tab(label='2', value='tab-2'),
    ], colors={
        "border": "white",
        "primary": "gold",
        "background": "cornsilk"
    }),
    html.Div(id='tabs-content-props')
])

@callback(Output('tabs-content-props', 'children'),
              Input('tabs-styled-with-props', 'value'))
def render_content(tab):
    if tab == 'tab-1':
        return html.Div([
            html.H3('Tab content 1')
        ])
    elif tab == 'tab-2':
        return html.Div([
            html.H3('Tab content 2')
        ])

# if __name__ == '__main__':
#     app.run(debug=True)