(数据科学学习手札103)Python+Dash快速web应用开发——页面布局篇
<blockquote><p>本文示例代码已上传至我的<code>Github</code>仓库https://github.com/CNFeffery/DataScienceStudyNotes</p>
</blockquote>
<ul>
<li>😋由我开源的先进<code>Dash</code>组件库<code>feffery-antd-components</code>正处于早期测试版本阶段,欢迎前往官网<code>http://fac.feffery.tech/</code>了解更多</li>
</ul>
<h1 id="1-简介">1 简介</h1>
<p> 这是我的系列教程<strong>Python+Dash快速web应用开发</strong>的第二期,在上一期中,我带领大家认识了什么是<code>Dash</code>,<code>Dash</code>可以做什么,以及<code>Dash</code>中最基本的一些概念,而今天开始,我将开始带领大家正式学习有关<code>Dash</code>的实用知识,以及各种奇淫巧技😋~</p>
<center><img src="https://img2020.cnblogs.com/blog/1344061/202101/1344061-20210115180536194-1929926857.png" style="zoom: 100%"></center><center><font size="2">图1</font></center>
<p> 今天的文章,我将带大家学习<code>Dash</code>中<strong>页面布局</strong>的先进方法,通过今天的文章,你将学会以非常简单的方式实现现代化的页面布局,下面让我们开始吧~</p>
<h1 id="2-为dash应用设计页面布局">2 为Dash应用设计页面布局</h1>
<p> 我们都知道,一个好的网页设计通常都需要编写<code>css</code>甚至<code>js</code>来定制前端内容,譬如非常流行的<code>bootstrap</code>框架。</p>
<center><img src="https://img2020.cnblogs.com/blog/1344061/202101/1344061-20210115180538920-1694785710.png" style="zoom: 100%"></center><center><font size="2">图2</font></center>
<p> 但我们既然想使用<code>Dash</code>来搭建web应用,很大的一个原因是不熟悉或者不想写繁琐的前端代码,而<code>Dash</code>的第三方拓展库中就有这么一个<code>Python</code>库——<code>dash-bootstrap-components</code>,借助它,我们就可以纯<code>Python</code>编程调用到 <code>bootstrap</code>框架中的诸多特性来让我们的web应用页面更美观。</p>
<p> 首先需要通过<code>pip install dash-bootstrap-components</code>来安装它,安装完成之后,我们来验证一下是否可以正常使用,推荐以<code>import dash_bootstrap_components as dbc</code>的方式导入:</p>
<blockquote>
<p>app1.py</p>
</blockquote>
<pre><code class="language-Python">import dash
import dash_bootstrap_components as dbc
app = dash.Dash(
__name__,
# 从国内可顺畅访问的cdn获取所需的原生bootstrap对应css
external_stylesheets=['https://cdn.staticfile.org/twitter-bootstrap/4.5.2/css/bootstrap.min.css']
)
app.layout = dbc.Alert(
"你好,dash_bootstrap_components!", color='success'
)
if __name__ == "__main__":
app.run_server()
</code></pre>
<p> 执行后打开所提示的网址,看到下列信息就说明安装成功:</p>
<center><img src="https://img2020.cnblogs.com/blog/1344061/202101/1344061-20210115180541097-191504108.png" style="zoom: 100%"></center><center><font size="2">图3</font></center>
<p> 这里我们使用到<code>dash.Dash()</code>中的参数<code>external_stylesheets</code>,用于引入外部的<code>css</code>文件,有了这些补充进来的<code>css</code>,我们才得以实现更多彩的样式,而除了上述填入<code>url</code>的方式之外,我更推荐的方式是在我们的<code>Dash</code>应用<code>.py</code>文件同级目录创建文件夹<code>assets</code>,放在这个目录中的文件会被<code>Dash</code>自动扫描到,也就无需填入<code>external_stylesheets</code>参数啦:</p>
<blockquote>
<p>app2.py</p>
</blockquote>
<pre><code class="language-Python">import dash
import dash_bootstrap_components as dbc
app = dash.Dash(__name__)
app.layout = dbc.Alert(
"你好,dash_bootstrap_components!", color='success'
)
if __name__ == "__main__":
app.run_server()
</code></pre>
<center><img src="https://img2020.cnblogs.com/blog/1344061/202103/1344061-20210313100244727-2067816949.png" style="zoom: 100%"></center><center><font size="2">图4</font></center>
<p> 这时在<code>Dash</code>页面抓包可以看到对应<code>bootstrap.min.css</code>的url信息指向域名下的对应目录:</p>
<center><img src="https://img2020.cnblogs.com/blog/1344061/202101/1344061-20210115180548186-967818202.png" style="zoom: 100%"></center><center><font size="2">图5</font></center>
<p> 这种方式最稳妥,不受网络波动影响,推荐大家养成好习惯。</p>
<p> 在测试完<code>dash-bootstrap-components</code>的可用性之后,接下来我们就开始学习构造页面布局。</p>
<h2 id="21-认识containerrow与col">2.1 认识Container()、Row()与Col()</h2>
<ul>
<li><strong>Container()</strong></li>
</ul>
<p> <code>dash-bootstrap-components</code>封装了<code>bootstrap</code>框架中的<strong>网格系统</strong>,我们在使用它进行布局时,首先要了解的是组件<code>Container()</code>,它是我们组织页面元素的容器,其参数<code>fluid</code>默认为False,会以两边填充空白区域的方式居中其内部嵌套的子元素:</p>
<blockquote>
<p>app3.py</p>
</blockquote>
<pre><code class="language-Python">import dash
import dash_bootstrap_components as dbc
import dash_core_components as dcc
import dash_html_components as html
app = dash.Dash(__name__)
app.layout = html.Div(
[
# fluid默认为False
dbc.Container(
[
dcc.Dropdown(),
'测试',
dcc.Dropdown()
]
),
html.Hr(), # 水平分割线
# fluid设置为True
dbc.Container(
[
dcc.Dropdown(),
'测试',
dcc.Dropdown()
],
fluid=True
)
]
)
if __name__ == "__main__":
app.run_server()
</code></pre>
<center><img src="https://img2020.cnblogs.com/blog/1344061/202101/1344061-20210115180551086-394038739.png" style="zoom: 100%"></center><center><font size="2">图6</font></center>
<p> 可以看到,第一个<code>Container()</code>部分呈现出两边空白填充中间居中的形式,而第二个则充满了整个水平方向。</p>
<ul>
<li><strong>Row()与Col()</strong></li>
</ul>
<p> 在上面所介绍的<code>Container()</code>之内,我们就可以按照<code>bootstrap</code>的网格系统进行内容的排布:<strong>行</strong>嵌套<strong>列</strong>,再向<strong>列</strong>内嵌套各种部件。</p>
<p> 而所谓的网格系统指的是每个<code>Row()</code>部件内部分成宽度相等的<strong>12</strong>份,传入的<code>Col()</code>部件具有参数<code>width</code>可以传入<strong>整数</strong>来分配对应数量的宽度,如下例:</p>
<blockquote>
<p>app4.py</p>
</blockquote>
<pre><code class="language-python">import dash
import dash_bootstrap_components as dbc
app = dash.Dash(__name__)
app.layout = dbc.Container(
[
dbc.Row(dbc.Col('第一行'),
style={
'background-color': 'lightgreen'
}),
dbc.Row(
[
dbc.Col('第二行第一列', width=6, style={'background-color': 'lightblue'}),
dbc.Col('第二行第二列', width=6, style={'background-color': 'lightskyblue'})
]
),
dbc.Row(
[
dbc.Col('第三行第一列', width=2, style={'background-color': 'HotPink'}),
dbc.Col('第三行第二列', width=10, style={'background-color': 'IndianRed'})
]
),
dbc.Row(
[
dbc.Col('第四行第一列', width=2, style={'background-color': 'HotPink'}),
dbc.Col('第四行第二列', width=2, style={'background-color': 'IndianRed'}),
dbc.Col('第四行第三列', width=2, style={'background-color': 'HotPink'})
]
),
dbc.Row(
[
dbc.Col('第五行第一列', width=2, style={'background-color': 'LightSteelBlue'}),
dbc.Col('第五行第二列', width=11, style={'background-color': 'MistyRose'}),
]
)
]
)
if __name__ == "__main__":
app.run_server()
</code></pre>
<center><img src="https://img2020.cnblogs.com/blog/1344061/202101/1344061-20210115180553275-773354071.png" style="zoom: 100%"></center><center><font size="2">图7</font></center>
<p> 可以看到当<code>Row()</code>部件下所有<code>Col()</code>部件宽度之和为12时是正好充满的,当宽度之和不足12时剩余的宽度会被空出来,而宽度之和若大于12,则会把导致宽度溢出的<code>Col()</code>部件挤到下一行中,所以我们在利用这种网格系统排布网页元素时要注意规范。</p>
<p> 而<strong>行部件</strong>也是可以嵌套到上一级<strong>列部件</strong>中的,因此如果你觉得12份不够自己实现更精确的宽度分配,就可以写个嵌套,实现固定宽度下再次划分12份,就像下面例子中我们:</p>
<blockquote>
<p>app5.py</p>
</blockquote>
<pre><code class="language-Python">import dash
import dash_bootstrap_components as dbc
app = dash.Dash(__name__)
app.layout = dbc.Container(
[
dbc.Row(dbc.Col('第一行'),
style={
'background-color': 'lightgreen'
}),
dbc.Row(
[
dbc.Col('第二行第一列', width=6, style={'background-color': 'lightblue'}),
dbc.Col(
dbc.Row(
[
dbc.Col('嵌套1', width=6, style={'background-color': 'Moccasin'}),
dbc.Col('嵌套2', width=3, style={'background-color': 'lightskyblue'}),
dbc.Col('嵌套3', width=3, style={'background-color': 'Moccasin'}),
]
),
width=6,
style={'background-color': 'lightskyblue'})
]
)
]
)
if __name__ == "__main__":
app.run_server()
</code></pre>
<center><img src="https://img2020.cnblogs.com/blog/1344061/202101/1344061-20210115180555267-1134184748.png" style="zoom: 100%"></center><center><font size="2">图8</font></center>
<p> 在get到这一小节的知识点后,我们就可以更规矩地编写页面内容,譬如写出下面这样的调查问卷就比较轻松(受限于篇幅,下面例子对应的<code>app6.py</code>不便放出代码,你可以在文章开头的<code>Github</code>仓库对应路径找到它):</p>
<blockquote>
<p>app6.py</p>
</blockquote>
<center><img src="https://img2020.cnblogs.com/blog/1344061/202101/1344061-20210115180557215-585852158.gif" style="zoom: 100%"></center><center><font size="2">图9</font></center>
<h2 id="22-row与col部件的进阶设置">2.2 Row()与Col()部件的进阶设置</h2>
<p> 通过上一小节的例子,想必你已经学习到如何在<code>Dash</code>中编排出<code>bootstrap</code>网格系统风格的页面,而为了在已初步编排好的网页基础上做更多实用优化,<code>dash-bootstrap-components</code>还为<code>Row()</code>与<code>Col()</code>部件提供了一些微调布局的参数:</p>
<ul>
<li><strong>利用order设定顺序</strong></li>
</ul>
<p> 我们在前面为<code>Col()</code>部件所设定的<code>width</code>参数都只是1到12之间的整数,其实它还可以接受字典输入,从而拓展其功能,原先的整数宽度输入就由<code>width=n</code>转化为<code>width={'size': n}</code>。</p>
<p> 除此之外,我们还可以添加<code>order</code>键参数来为同一个<code>Row()</code>下的部件设置顺序,接受三种输入:<code>'first'</code>表示置于当前行第一列,<code>'last'</code>表示置于当前行最后一列,而1到12的整数则可以直接以序号编排列部件顺序。</p>
<p> 结合下面这个简单的例子理解这部分内容:</p>
<blockquote>
<p>app7.py</p>
</blockquote>
<pre><code class="language-Python">import dash
import dash_bootstrap_components as dbc
import dash_html_components as html
app = dash.Dash(__name__)
app.layout = html.Div(
dbc.Container(
[
html.Br(),
html.Br(),
html.Br(),
dbc.Row(
[
dbc.Col('1', width=2, style={'background-color': 'lightblue'}),
dbc.Col('2', width=2, style={'background-color': 'lightskyblue'}),
dbc.Col('3', width=2, style={'background-color': '#e88b00'}),
dbc.Col('4', width=2, style={'background-color': '#8c8c8c'})
]
),
html.Br(),
dbc.Row(
[
dbc.Col('order=last', width={'size': 2, 'order': 'last'}, style={'background-color': 'lightblue'}),
dbc.Col('order=2', width={'size': 2, 'order': 2}, style={'background-color': 'lightskyblue'}),
dbc.Col('order=1', width={'size': 2, 'order': 1}, style={'background-color': '#e88b00'}),
dbc.Col('order=first', width={'size': 2, 'order': 'first'}, style={'background-color': '#8c8c8c'})
]
)
]
)
)
if __name__ == '__main__':
app.run_server()
</code></pre>
<p> 可以很直观地看出<code>order</code>参数对列部件顺序的影响:</p>
<center><img src="https://img2020.cnblogs.com/blog/1344061/202101/1344061-20210115180559058-52145627.png" style="zoom: 100%"></center><center><font size="2">图10</font></center>
<ul>
<li><strong>利用offset设置偏移</strong></li>
</ul>
<p> 列部件的<code>width</code>参数字典中还可以使用键值对参数<code>offset</code>,传入1到12的整数,它的作用是为对应的<code>Col()</code>部件左侧增加对应宽度的位移,就像下面的例子一样:</p>
<blockquote>
<p>app8.py</p>
</blockquote>
<pre><code class="language-Python">import dash
import dash_bootstrap_components as dbc
import dash_html_components as html
app = dash.Dash__name__)
app.layout = html.Div(
dbc.Container(
[
html.Br(),
html.Br(),
html.Br(),
dbc.Row(
[
dbc.Col('1', width=2, style={'background-color': 'lightblue'}),
dbc.Col('2', width=2, style={'background-color': 'lightskyblue'}),
dbc.Col('3', width=2, style={'background-color': '#e88b00'}),
dbc.Col('4', width=2, style={'background-color': '#8c8c8c'})
],
style={'border': '1px solid black'}
),
html.Br(),
dbc.Row(
[
dbc.Col('offset=1', width={'size': 2, 'offset': 1}, style={'background-color': 'lightblue'}),
dbc.Col('offset=2', width={'size': 2, 'offset': 2}, style={'background-color': 'lightskyblue'}),
dbc.Col('3', width=2, style={'background-color': '#e88b00'}),
dbc.Col('offset=1', width={'size': 2, 'offset': 1}, style={'background-color': '#8c8c8c'})
],
style={'border': '1px solid black'}
)
]
)
)
if __name__ == '__main__':
app.run_server()
</code></pre>
<p> 为了更明显,我给每个<code>Row()</code>部件加了轮廓线,可以看到效果非常直观:</p>
<center><img src="https://img2020.cnblogs.com/blog/1344061/202101/1344061-20210115180601349-1313076426.png" style="zoom: 100%"></center><center><font size="2">图11</font></center>
<ul>
<li><strong>设置水平对齐方式</strong></li>
</ul>
<p> 在前面的内容中,我们在同一个<code>Row()</code>部件下组织的所有<code>Col()</code>部件,其顺序都是从左到右一个紧贴下一个排布的,即使设置了<code>offset</code>参数,也只是插空后紧贴。</p>
<p> 但在很多页面布局需求中需要对于同一行的多个列元素设置<strong>对齐方式</strong>,这在<code>dash-bootstrap-components</code>中可以通过对<code>Row()</code>部件设置参数<code>justify</code>来实现,可选项有<code>'start'</code>、<code>'center'</code>、<code>'end'</code>、<code>'between'</code>以及<code>'around'</code>五种,每种产生的效果如下面的例子:</p>
<blockquote>
<p>app9.py</p>
</blockquote>
<pre><code class="language-Python">import dash
import dash_bootstrap_components as dbc
import dash_html_components as html
app = dash.Dash(__name__)
app.layout = html.Div(
dbc.Container(
[
html.Br(),
html.Br(),
html.Br(),
dbc.Row(
[
dbc.Col('start', width=3, style={'border': '1px solid black'}),
dbc.Col('start', width=3, style={'border': '1px solid black'}),
dbc.Col('start', width=3, style={'border': '1px solid black'})
],
justify='start'
),
html.Br(),
dbc.Row(
[
dbc.Col('center', width=3, style={'border': '1px solid black'}),
dbc.Col('center', width=3, style={'border': '1px solid black'}),
dbc.Col('center', width=3, style={'border': '1px solid black'})
],
justify='center'
),
html.Br(),
dbc.Row(
[
dbc.Col('end', width=3, style={'border': '1px solid black'}),
dbc.Col('end', width=3, style={'border': '1px solid black'}),
dbc.Col('end', width=3, style={'border': '1px solid black'})
],
justify='end'
),
html.Br(),
dbc.Row(
[
dbc.Col('between', width=3, style={'border': '1px solid black'}),
dbc.Col('between', width=3, style={'border': '1px solid black'}),
dbc.Col('between', width=3, style={'border': '1px solid black'})
],
justify='between'
),
html.Br(),
dbc.Row(
[
dbc.Col('around', width=3, style={'border': '1px solid black'}),
dbc.Col('around', width=3, style={'border': '1px solid black'}),
dbc.Col('around', width=3, style={'border': '1px solid black'})
],
justify='around'
)
],
# 为Container两边添加参考线
style={'border-left': '1px solid red', 'border-right': '1px solid red'}
)
)
if __name__ == '__main__':
app.run_server()
</code></pre>
<center><img src="https://img2020.cnblogs.com/blog/1344061/202101/1344061-20210115180603262-400622478.png" style="zoom: 100%"></center><center><font size="2">图12</font></center>
<h2 id="23-实际案例">2.3 实际案例</h2>
<p> 通过对上面知识内容的学习,我们掌握了如何基于拓展库<code>dash-bootstrap-components</code>,在<code>Dash</code>中实现<code>bootstrap</code>的网格系统。</p>
<p> 下面我们来利用今天学到的知识点,搭建下图所示的登录页面,其中涉及到一些还未给大家介绍的知识点,但很简单,之后的课程会介绍,而涉及到一些额外的css的内容我都已写好注释非常简单~</p>
<center><img src="https://img2020.cnblogs.com/blog/1344061/202101/1344061-20210115180605125-632203297.png" style="zoom: 100%"></center><center><font size="2">图13</font></center>
<p> 对应代码如下:</p>
<blockquote>
<p>app10.py</p>
</blockquote>
<pre><code class="language-Python">import dash
import dash_html_components as html
import dash_bootstrap_components as dbc
app = dash.Dash(__name__)
app.layout = html.Div(
[
html.Br(),
html.Br(),
html.Br(),
html.Br(),
html.Br(),
html.Br(),
html.Br(),
html.Br(),
dbc.Container(
[
dbc.Row(style={'height': '30px'}),# 利用css设置高度
dbc.Row(
dbc.Col('Email address')
),
dbc.Row(
dbc.Col(dbc.Input(placeholder='Enter email'))
),
dbc.Row(
dbc.Col('Password')
),
dbc.Row(
dbc.Col(dbc.Input(placeholder='Enter Password'))
),
dbc.Row(
dbc.Col(
[
'By signing up you accept our ',
html.A('Terms Of Use', href='#')
],
width={'size': 10, 'offset': 1},
style={'text-align': 'center'}# 利用css设置文字居中
),
style={'margin': '6px'}# 利用css设置上下留白高度
),
dbc.Row(
dbc.Col(
# 利用css实现圆角矩形效果
dbc.Button('LOGIN', style={'border-radius': '18px'}, block=True),
width={'size': 8, 'offset': 2},
style={'text-align': 'center'}
)
),
dbc.Row(
[
dbc.Col(html.Hr()),
html.P('or', style={'text-align': 'center', 'margin': 0}),
dbc.Col(html.Hr())
]
),
dbc.Row(
dbc.Col(
dbc.Button(
'Signup using Google',
style={'border-radius': '18px'},
block=True,
outline=True
),
width={'size': 8, 'offset': 2},
style={'text-align': 'center'}
)
),
dbc.Row(
dbc.Col(
[
"Don't have account? ",
html.A('Sign up here', href='#')
],
width={'size': 10, 'offset': 1},
style={'text-align': 'center'}
),
style={'margin': '6px'}
),
html.Br(),
],
style={
'background-color': '#ededef',# 设置背景颜色
'max-width': '480px',# 为Container部件设置最大宽度
'border-radius': '12px'
}
)
]
)
if __name__ == '__main__':
app.run_server()
</code></pre>
<hr>
<p> 以上就是本文的全部内容,欢迎在评论区与我进行讨论,<strong>点赞</strong>越多下一期更新越快哦😋~</p><br><br>
来源:https://www.cnblogs.com/feffery/p/14276803.html
頁:
[1]