### UI 模塊
Tornado 支持一些 UI 模塊,它們可以幫你創建標準的,易被重用的應用程序級的 UI 組件。 這些 UI 模塊就跟特殊的函數調用一樣,可以用來渲染頁面組件,而這些組件可以有自己的 CSS 和 JavaScript。
例如你正在寫一個博客的應用,你希望在首頁和單篇文章的頁面都顯示文章列表,你可以創建 一個叫做 `Entry` 的 UI 模塊,讓他在兩個地方分別顯示出來。首選需要為你的 UI 模塊 創建一個 Python 模組文件,就叫 `uimodules.py` 好了:
```
class Entry(tornado.web.UIModule):
def render(self, entry, show_comments=False):
return self.render_string(
"module-entry.html", entry=entry, show_comments=show_comments)
```
然后通過 `ui_modules` 配置項告訴 Tornado 在應用當中使用 `uimodules.py`:
```
class HomeHandler(tornado.web.RequestHandler):
def get(self):
entries = self.db.query("SELECT * FROM entries ORDER BY date DESC")
self.render("home.html", entries=entries)
class EntryHandler(tornado.web.RequestHandler):
def get(self, entry_id):
entry = self.db.get("SELECT * FROM entries WHERE id = %s", entry_id)
if not entry: raise tornado.web.HTTPError(404)
self.render("entry.html", entry=entry)
settings = {
"ui_modules": uimodules,
}
application = tornado.web.Application([
(r"/", HomeHandler),
(r"/entry/([0-9]+)", EntryHandler),
], **settings)
```
在 `home.html` 中,你不需要寫繁復的 HTML 代碼,只要引用 `Entry` 就可以了:
```
{% for entry in entries %}
{% module Entry(entry) %}
{% end %}
```
在 `entry.html` 里面,你需要使用 `show_comments` 參數來引用 `Entry` 模塊,用來 顯示展開的 `Entry` 內容:
```
{% module Entry(entry, show_comments=True) %}
```
你可以為 UI 模型配置自己的 CSS 和 JavaScript ,只要復寫 `embedded_css`、 `embedded_javascript`、`javascipt_files`、`css_files` 就可以了:
```
class Entry(tornado.web.UIModule):
def embedded_css(self):
return ".entry { margin-bottom: 1em; }"
def render(self, entry, show_comments=False):
return self.render_string(
"module-entry.html", show_comments=show_comments)
```
即使一頁中有多個相同的 UI 組件,UI 組件的 CSS 和 JavaScript 部分只會被渲染一次。 CSS 是在頁面的 `<head>` 部分,而 JavaScript 被渲染在頁面結尾 `</body>` 之前的位 置。
在不需要額外 Python 代碼的情況下,模板文件也可以當做 UI 模塊直接使用。 例如前面的例子可以以下面的方式實現,只要把這幾行放到 `module-entry.html` 中就可以了:
```
{{ set_resources(embedded_css=".entry { margin-bottom: 1em; }") }}
<!-- more template html... -->
```
這個修改過的模塊式模板可以通過下面的方法調用:
```
{% module Template("module-entry.html", show_comments=True) %}
```
`set_resources` 函數只能在 `{% module Template(...) %}` 調用的模板中訪問到。 和 `{% include ... %}` 不同,模塊式模板使用了和它們的上級模板不同的命名 空間——它們只能訪問到全局模板命名空間和它們自己的關鍵字參數。