本文翻譯自The Flask Mega-Tutorial Part XI: Facelift
這是Flask Mega-Tutorial系列的第十一部分,我將告訴你如何用基於Bootstrap用戶界面框架的新模板替換基礎的HTML模板。
你把玩Microblog應用也有一段時間了,所以我相信你已經注意到,我沒有花太多時間來美化它,說得更具體點,我根本沒有花時間。 所有的模板只使用了基礎樣式,沒有任何自定義的展現。 這對於我來說卻非常有用,因為我可以專注於應用的實際邏輯,不用分心於編寫好看的HTML和CSS代碼。
但是我已經長期關注應用的后端部分一段時間了。 因此在本章中,我暫停一下后端的工作,並花點時間向你展示如何使應用看起來更加優雅和專業。
本章將與之前的章節略有不同,因為我不會像平常解說Python那樣,事無巨細,一一道來,畢竟Python才是本教程的主要內容。 創建漂亮的網頁是一個很廣泛的話題,而與Python Web的后端開發很大程度上無關,因此我將討論一些基本的指導方針和想法,你可以通過重新設計應用的外觀來研究和學習它。
本章的GitHub鏈接為:Browse, Zip, Diff.
CSS框架
雖然我們可以爭辯說寫代碼不容易,但是與那些必須讓網頁在所有Web瀏覽器上具有良好一致外觀的網頁設計師相比,我們的痛苦不值一提。 雖然近年來這種情況得到一定程度的緩解,但是在一些瀏覽器中仍然存在着晦澀的錯誤或奇怪的設定,這使得設計網頁的任務變得非常困難。 如果還需要兼容屏幕限制設備(諸如平板電腦和智能手機)的瀏覽器,則更加困難。
如果你和我一樣,只是一個想創建出規范網頁的開發人員,沒有時間或興趣去學習底層機制並通過編寫原生HTML和CSS來實現它,那么唯一可行的解決方案是使用CSS框架來簡化任務。 通過這種方式,你會失去一些創造性的自由,但另一方面,無需通過太多的功夫就可以讓網頁在所有瀏覽器中看起來都不錯。 CSS框架為普通類型的用戶界面元素提供了高級CSS類的集合,其中包含預定義樣式。 大多數這樣的框架還提供JavaScript插件,以實現不能純粹使用HTML和CSS來完成的功能。
Bootstrap簡介
最受歡迎的CSS框架之一是由Twitter推出的Bootstrap。 如果你想看看這個框架可以設計的頁面類型,文檔有一些示例。
這些是使用Bootstrap來設置網頁風格的一些好處:
- 在所有主流網頁瀏覽器中都有相似的外觀
- 自動處理PC桌面,平板電腦和手機屏幕尺寸
- 可定制的布局
- 精心設計的導航欄,表單,按鈕,警示,彈出窗口等
使用Bootstrap最直接的方法是簡單地在你的基本模板中導入bootstrap.min.css文件。 可以下載此文件並將其添加到你的項目中,或直接從CDN導入。 然后,你可以根據其文檔開始使用它提供的通用CSS類,實在是太棒了。 你可能還需要導入包含框架JavaScript代碼的bootstrap.min.js文件,以便使用最先進的功能。
幸運的是,有一個名為Flask-Bootstrap的Flask插件,它提供了一個已准備好的基礎模板,該模板引入了Bootstrap框架。 讓我們來安裝這個擴展:
1 (venv) $ pip install flask-bootstrap
使用Flask-Bootstrap
Flask-Bootstrap需要像大多數其他Flask插件一樣被初始化:
app/init.py: Flask-Bootstrap實例。
1 # ... 2 from flask_bootstrap import Bootstrap 3 4 app = Flask(__name__) 5 # ... 6 bootstrap = Bootstrap(app)
在初始化插件之后,bootstrap/base.html模板就會變為可用狀態,你可以使用extends
子句從應用模板中引用。
但是,回顧一下,我已經使用了extends
子句來繼承我的基礎模板,這使我可以將頁面的公共部分放在一個地方。 base.html模板定義了導航欄,其中包含幾個鏈接,並且還導出了一個content
塊。 應用中的所有其他模板都從基礎模板繼承,並為內容塊提供頁面的主要內容。
那么我怎樣才能適配Bootstrap基礎模板呢? 解決方案是從使用兩個層級到使用三個層級。 bootstrap/base.html模板提供頁面的基本結構,其中引入了Bootstrap框架文件。 這個模板為派生的模板定義了一些塊,例如title
,navbar
和content
(參見塊的完整列表)。 我將更改base.html模板以從bootstrap/base.html派生,並提供title
,navbar
和content
塊的實現。 反過來,base.html將為從其派生的模板導出app_content
塊以定義頁面內容。
下面你可以看到從Bootstrap基礎模板派生的base.html的代碼。 請注意,此列表不包含導航欄的整個HTML,但你可以在GitHub上或下載本章的代碼來查看完整的實現。
app/templates/base.html:重新設計后的基礎模板。
1 {% extends 'bootstrap/base.html' %} 2 3 {% block title %} 4 {% if title %}{{ title }} - Microblog{% else %}Welcome to Microblog{% endif %} 5 {% endblock %} 6 7 {% block navbar %} 8 <nav class="navbar navbar-default"> 9 ... navigation bar here (see complete code on GitHub) ... 10 </nav> 11 {% endblock %} 12 13 {% block content %} 14 <div class="container"> 15 {% with messages = get_flashed_messages() %} 16 {% if messages %} 17 {% for message in messages %} 18 <div class="alert alert-info" role="alert">{{ message }}</div> 19 {% endfor %} 20 {% endif %} 21 {% endwith %} 22 23 {# application content needs to be provided in the app_content block #} 24 {% block app_content %}{% endblock %} 25 </div> 26 {% endblock %}
從中你可以看到我如何從bootstrap/base.html派生此模板,接下來分別實現了頁面標題、導航欄和頁面內容的這三個模塊。
title
塊需要使用<title>
標簽來定義用於頁面標題的文本。 對於這個塊我簡單地挪用了原始基本模板中<title>
標簽內部的邏輯。
navbar
塊是一個可選塊,用於定義導航欄。 對於此塊,我調整了Bootstrap導航欄文檔中的示例,以便它在左側展示網站品牌,跟着是Home和Explore的鏈接。 然后我添加了個人主頁和登錄或注銷鏈接並使其與頁面的右邊界對齊。 正如我上面提到的,我在上面的例子中省略了HTML,但是你可以從本章的下載包中獲得完整的base.html模板。
最后,在content
塊中,我定義了一個頂級容器,並在其中設定了呈現閃現消息的邏輯,這些消息現在將顯示為Bootstrap警示的樣式。 接下來是一個新的app_content
塊,這個塊用於從其派生的模板來定義他們自己的內容。
所有頁面模板的原始版本在名為content
的塊中定義了它們的內容。 正如你在上面看到的,Flask-Bootstrap使用名為content
的塊,所以我將我的內容塊重命名為app_content
。 所以我所有的模板都必須重命名為使用app_content
作為它們的內容塊。 例如,這是404.html模板的修改后版本的展示:
app/templates/404.html:重新設計后的404錯誤模板。
1 {% extends "base.html" %} 2 3 {% block app_content %} 4 <h1>File Not Found</h1> 5 <p><a href="{{ url_for('index') }}">Back</a></p> 6 {% endblock %}
渲染Bootstrap表單
Flask-Bootstrap在渲染表單這方面做得非常出色。 Flask-Bootstrap不需要逐個設置表單字段,而是使用一個接受Flask-WTF表單對象作為參數的宏,並以Bootstrap樣式渲染出完整的表單。
下面你可以看到重新設計后的register.html模板:
app/templates/register.html::用戶注冊模板。
{% extends "base.html" %} {% import 'bootstrap/wtf.html' as wtf %} {% block app_content %} <h1>Register</h1> <div class="row"> <div class="col-md-4"> {{ wtf.quick_form(form) }} </div> </div> {% endblock %}
是不是很棒? 頂端附近的import
語句與Python導入類似。 這增加了一個wtf.quick_form()
宏,它在單行代碼中渲染完整的表單,包括對顯示驗證錯誤的支持,並且適配Bootstrap框架的所有樣式。
再一次地,我不會向你展示我為應用中的其他表單所做的所有更改,但這些更改都是可以在GitHub上下載或檢查到的。
渲染用戶動態
單條用戶動態的渲染邏輯被提取到名為_post.html的子模板中。 我只需要在這個模板上做一些很小的調整,就可以使其在Bootstrap下看起來很棒了。
app/templates/_post.html: 重新設計后的用戶動態子模板。
1 <table class="table table-hover"> 2 <tr> 3 <td width="70px"> 4 <a href="{{ url_for('user', username=post.author.username) }}"> 5 <img src="{{ post.author.avatar(70) }}" /> 6 </a> 7 </td> 8 <td> 9 <a href="{{ url_for('user', username=post.author.username) }}"> 10 {{ post.author.username }} 11 </a> 12 says: 13 <br> 14 {{ post.body }} 15 </td> 16 </tr> 17 </table>
渲染分頁鏈接
分頁鏈接是Bootstrap提供直接支持的另一個方面。 為此,我再一次訪問Bootstrap 文檔,並修改了其中的一個示例。 以下是在index.html頁面中的分頁鏈接的代碼:
app/templates/index.html: 重新設計后的分頁鏈接。
1 ... 2 <nav aria-label="..."> 3 <ul class="pager"> 4 <li class="previous{% if not prev_url %} disabled{% endif %}"> 5 <a href="{{ prev_url or '#' }}"> 6 <span aria-hidden="true">←</span> Newer posts 7 </a> 8 </li> 9 <li class="next{% if not next_url %} disabled{% endif %}"> 10 <a href="{{ next_url or '#' }}"> 11 Older posts <span aria-hidden="true">→</span> 12 </a> 13 </li> 14 </ul> 15 </nav>
請注意,在分頁鏈接的實現中,當某個方向沒有更多內容時,不是隱藏該鏈接,而是使用禁用狀態,這會使該鏈接顯示為灰色。
類似的更改需要應用於user.html,但我不打算展示在此處。 本章的下載包中包含這些更改。
對比
請下載本章的zip文件並更新應用。
下面你可以對照幾張美化前后的圖片來觀察轉變情況。 請記住,這種轉變是在不改變一行應用邏輯代碼的情況下實現的!