# 模板語法規則
### Nunjucks模板語法
## 變量
變量會從模板上下文獲取,如果你想顯示一個變量可以:
~~~
{{ username }}
~~~
會從上下文查找 username 然后顯示,可以像 javascript 一樣獲取變量的屬性 (可使用點操作符或者中括號操作符):
~~~
{{ foo.bar }}
{{ foo["bar"] }}
~~~
如果變量的值為 undefined 或 null 將不顯示,引用到 undefined 或 null 對象也是如此 (如 foo 為 undefined,{{ foo }}, {{ foo.bar }}, {{ foo.bar.baz }} 也不顯示)。
~~~
{{ foo | title }}
{{ foo | join(",") }}
{{ foo | replace("foo", "bar") | capitalize }}
~~~
第三個例子展示了鏈式過濾器,最終會顯示 "Bar",第一個過濾器將 "foo" 替換成 "bar",第二個過濾器將首字母大寫。
Nunjucks 提供了一些內置的過濾器,你也可以自定義過濾器。
~~~
{% block header %}
This is the default content
{% endblock %}
<section class="left">
{% block left %}{% endblock %}
</section>
<section class="right">
{% block right %}
This is more content
{% endblock %}
</section>
~~~
然后再寫一個模板繼承他
~~~
{% extends "parent.html" %}
{% block left %}
This is the left side!
{% endblock %}
{% block right %}
This is the right side!
{% endblock %}
~~~
以下為渲染結果
~~~
This is the default content
<section class="left">
This is the left side!
</section>
<section class="right">
This is the right side!
</section>
~~~
你可以將繼承的模板設為一個變量,這樣就可以動態指定繼承的模板。這個變量既可以是個指向模板文件的字符串,也可以是個模板編譯后所生成的對象(需要添加上下文環境)。因此你可以通過設置上下文變量,從而在渲染時動態地改變所要繼承的模板。
~~~
{% extends parentTemplate %}
~~~
繼承功能使用了 extends 和 block 標簽,jinja2 文檔中有更細節的描述。
## super
你可以通過調用super從而將父級區塊中的內容渲染到子區塊中。如果在前面的例子中你的子模板是這樣的:
~~~
{% block right %}
{{ super() }}
Right side!
{% endblock %}
~~~
這個區塊的渲染結果將是:
~~~
This is more content
Right side!
~~~
### 自定義。
## **if**
if 為分支語句,與 javascript 中的 if 類似。
~~~
{% if variable %}
It is true
{% endif %}
~~~
如果 variable 定義了并且為 true (譯者注:這里并非布爾值,和 javascript 的處理是一樣的) 則會顯示 "It is true",否則什么也不顯示。
~~~
{% if hungry %}
I am hungry
{% elif tired %}
I am tired
{% else %}
I am good!
{% endif %}
~~~
在內聯表達式(inline expression)中也可以使用 if。
## **for**
for 可以遍歷數組 (arrays) 和對象 (dictionaries)。
如果你使用的自定義模板加載器為異步的可查看 asyncEach
`var items = [{ title: "foo", id: 1 }, { title: "bar", id: 2}];`
~~~
<h1>Posts</h1>
<ul>
{% for item in items %}
<li>{{ item.title }}</li>
{% else %}
<li>This would display if the 'item' collection were empty</li>
{% endfor %}
</ul>
~~~
上面的示例通過使用items數組中的每一項的title屬性顯示了所有文章的標題。如果items數組是空數組的話則會渲染else語句中的內容。
你還可以遍歷對象:
~~~
var food = {
'ketchup': '5 tbsp',
'mustard': '1 tbsp',
'pickle': '0 tbsp'
};
{% for ingredient, amount in food %}
Use {{ amount }} of {{ ingredient }}
{% endfor %}
~~~
dictsort 過濾器可將對象排序 (new in 0.1.8)
除此之外,Nunjucks 會將數組解開,數組內的值對應到變量 (new in 0.1.8)
`var points = [[0, 1, 2], [5, 6, 7], [12, 13, 14]];`
~~~
{% for x, y, z in points %}
Point: {{ x }}, {{ y }}, {{ z }}
{% endfor %}
~~~
在循環中可獲取一些特殊的變量
* loop.index: 當前循環數 (1 indexed)
* loop.index0: 當前循環數 (0 indexed)
* loop.revindex: 當前循環數,從后往前 (1 indexed)
* loop.revindex0: 當前循環數,從后往前 (0 based)
* loop.first: 是否第一個
* loop.last: 是否最后一個
* loop.length: 總數
## **asyncEach**
> 這個是適用于異步模板,請讀[文檔](http://mozilla.github.io/nunjucks/cn/api.html#asynchronous-support)。
asyncEach 為 for 的異步版本,只有當使用自定義異步模板加載器的時候才使用,否則請不要使用。異步過濾器和擴展也需要他。如果你在循環中使用了異步過濾器的話,Nunjucks就會在內部自動將循環轉換成 asyncEach。
asyncEach 和 for 的使用方式一致,但他支持循環的異步控制。將兩者區分的原因是性能,大部分人使用同步模板,將 for 轉換成原生的 for 語句會快很多。
編譯時 nunjuck 不用關心模板是如何加載的,所以無法決定 include 是同步或異步。這也是為什么Nunjucks無法自動將普通的循環語句轉換成異步循環語句的原因,所以如果你要使用異步模板加載器的話,就需要使用 asyncEach。
> // If you are using a custom loader that is async, you need asyncEach
> var env = new nunjucks.Environment(AsyncLoaderFromDatabase, opts);
~~~
<h1>Posts</h1>
<ul>
{% asyncEach item in items %}
{% include "item-template.html" %}
{% endeach %}
</ul>
~~~
## **asyncAll**
> 這個是適用于異步模板,請讀[文檔](http://mozilla.github.io/nunjucks/cn/api.html#asynchronous-support)。
asyncAll 和 asyncEach 類似,但 asyncAll 會并行的執行,并且每項的順序仍然會保留。除非使用異步的過濾器、擴展或加載器,否則不要使用。
如果你寫了一個 lookup 的過濾器用來從數據庫獲取一些文本,使用 asyncAll 可以并行渲染。
~~~
<h1>Posts</h1>
<ul>
{% asyncAll item in items %}
<li>{{ item.id | lookup }}</li>
{% endall %}
</ul>
~~~
如果 lookup 是一個異步的過濾器,那么可能會比較慢(如從磁盤獲取些數據)。asyncAll 會減少執行的時間,他會并行執行所有的異步操作,當所有的操作完成后才會繼續渲染頁面。
## **macro**
宏 (macro) 可以定義可復用的內容,類似與編程語言中的函數,看下面的示例:
~~~
{% macro field(name, value='', type='text') %}
<div class="field">
<input type="{{ type }}" name="{{ name }}"
value="{{ value | escape }}" />
</div>
{% endmacro %}
~~~
現在 field 可以當作函數一樣使用了:
~~~
{{ field('user') }}
{{ field('pass', type='password') }}
~~~
支持關鍵字參數,通過鏈接查看具體使用方式。
還可以從其他模板 import 宏,可以使宏在整個項目中復用。
> **重要:如果你使用異步 API,請注意你 不能 在宏中做任何異步的操作,因為宏只是像函數一樣被簡單地調用。將來我們可能會提供一種異步的宏調用方式,但現在這么使用是不被支持的。**
## **set**
set 可以設置和修改變量。
~~~
{{ username }}
{% set username = "joe" %}
{{ username }}
~~~
如果 username 初始化的時候為 "james', 最終將顯示 "james joe"。
可以設置新的變量,并一起賦值。
~~~
{% set x, y, z = 5 %}
~~~
如果在頂級作用域使用 set,將會改變全局的上下文中的值。如果只在某個作用域 (像是include或是macro) 中使用,則只會影響該作用域。
同樣地,你也可以使用區塊賦值將一個區塊的內容儲存在一個變量中。
它的語法和標準的set語法相似,只不過你不需要用=。區塊中從頭到{% endset %}之間的內容都會被捕獲,并作為值來使用。
在某些情境下,你可以用這種語法來替代宏:
~~~
{% set standardModal %}
{% include 'standardModalData.html' %}
{% endset %}
<div class="js-modal" data-modal="{{standardModal | e}}">
~~~
## **extends**
extends 用來指定模板繼承,被指定的模板為父級模板,查看模板繼承。
~~~
{% extends "base.html" %}
~~~
你可以將繼承的模板設為一個變量,這樣就可以動態指定繼承的模板。這個變量既可以是個指向模板文件的字符串,也可以是個模板編譯后所生成的對象(需要添加上下文環境)。因此你可以通過設置上下文變量,從而在渲染時動態地改變所要繼承的模板。
~~~
{% extends parentTemplate %}
~~~
extends也可以接受任意表達式,只要它最終返回一個字符串或是模板所編譯成的對象:
~~~
{% extends name + ".html" %}`.
~~~
## **block**
區塊(block) 定義了模板片段并標識一個名字,在模板繼承中使用。父級模板可指定一個區塊,子模板覆蓋這個區塊,查看模板繼承。
~~~
{% block css %}
<link rel="stylesheet" href="app.css" />
{% endblock %}
~~~
可以在循環中定義區塊
~~~
{% for item in items %}
{% block item %}{{ item }}{% endblock %}
{% endfor %}
~~~
子模板可以覆蓋 item 區塊并改變里面的內容。
~~~
{% extends "item.html" %}
{% block item %}
The name of the item is: {{ item.name }}
{% endblock %}
~~~
在區塊中,你可以調用特殊的super函數。它會渲染父級區塊中的內容。具體請查看super。
## **include**
include 可引入其他的模板,可以在多模板之間共享一些小模板,如果某個模板已使用了繼承那么 include 將會非常有用。
~~~
{% include "item.html" %}
~~~
可在循環中引入模板
~~~
{% for item in items %}
{% include "item.html" %}
{% endfor %}
~~~
這一點可以幫助我們把模板切分成更小的部分,從而使得在瀏覽器上,當我們需要改變頁面時,我們可以渲染這些小部分的模板,而非一整個的大的模板。
include 可以接受任意表達式,只要它最終返回一個字符串或是模板所編譯成的對象: `{% include name + ".html" as obj %}`.
在某些情況下,我們可能希望在模板文件不存在時不要拋出異常。對于這類情況,我們可以使用ignore missing來略過這些異常:
~~~
{% include "missing.html" ignore missing %}
~~~
被包含的模版自身可以擴展(extends)另一個模版(因此你可以讓一系列相關聯的模版繼承同一種結構)。 一個被包含的模版并不會改變包含它的模版的區塊結構,它有一個分離的繼承樹和塊級命名空間。換言之, 在渲染時,include并不 不是 將被包含模版代碼拉取到包含它的模版中的預處理器。相對的,它對被 包含的模版觸發了一次的分離渲染,然后再將渲染的結果引入。
## **import**
import 可加載不同的模板,可使你操作模板輸出的數據,模板將會輸出宏 (macro) 和在頂級作用域進行的賦值 (使用 set)。
被 import 進來的模板沒有當前模板的上下文,所以無法使用當前模板的變量,
創建一個叫 forms.html 如下所示
~~~
{% macro field(name, value='', type='text') %}
<div class="field">
<input type="{{ type }}" name="{{ name }}"
value="{{ value | escape }}" />
</div>
{% endmacro %}
{% macro label(text) %}
<div>
<label>{{ text }}</label>
</div>
{% endmacro %}
~~~
我們可以 import 這個模板并將模板的輸出綁定到變量 forms 上,然后就可以使用這個變量了:
~~~
{% import "forms.html" as forms %}
{{ forms.label('Username') }}
{{ forms.input('user') }}
{{ forms.label('Password') }}
{{ forms.input('pass', type='password') }}
~~~
也可以使用 from import 從模板中 import 指定的值到當前的命名空間:
~~~
{% from "forms.html" import input, label as description %}
{{ description('Username') }}
{{ input('user') }}
{{ description('Password') }}
{{ input('pass', type='password') }}
~~~
import 可以接受任意表達式,只要它最終返回一個字符串或是模板所編譯成的對象: `{% import name + ".html" as obj %}`.
## **raw**
如果你想輸出一些 Nunjucks 特殊的標簽 (如 {{),可以使用 {{),可以使用` {% raw %}` 將所有的內容輸出為純文本。
## **filter**
filter區塊允許我們使用區塊中的內容來調用過濾器。不同于使用|語法,它會將區塊渲染出的內容傳遞給過濾器。
~~~
{% filter title %}
may the force be with you
{% endfilter %}
{% filter replace("force", "forth") %}
may the force be with you
{% endfilter %}
~~~
切記:你不能在這些區塊中進行任何異步操作。
## **call**
call區塊允許你使用標簽之間的內容來調用一個宏。這在你需要給宏傳入大量內容時是十分有用的。在宏中,你可以通過caller()來獲取這些內容。
~~~
{% macro add(x, y) %}
{{ caller() }}: {{ x + y }}
{% endmacro%}
{% call add(1, 2) -%}
The result is
{%- endcall %}
~~~
上面的例子將會輸出"The result is: 3"。
~~~
{{ foo(1, 2, bar=3, baz=4) }}
~~~
bar 和 baz 為關鍵字參數,Nunjucks 將他們轉換成一個對象作為最后一個參數傳入,等價于 javascript 的如下調用:
~~~
foo(1, 2, { bar: 3, baz: 4})
~~~
因為這使一個標準的調用轉換,所以適用于所有的符合預期的函數和過濾器。查看 API 章節獲得更多信息。
定義宏的時候也可以使用關鍵字參數,定義參數值時可設置默認值。Nunjucks 會自動將關鍵字參數與宏里定義的值做匹配。
~~~
{% macro foo(x, y, z=5, w=6) %}
{{ x }}, {{ y }}, {{ z }}, {{ w}}
{% endmacro %}
{{ foo(1, 2) }} -> 1, 2, 5, 6
{{ foo(1, 2, w=10) }} -> 1, 2, 5, 10
~~~
在宏中還可以混合使用位置參數 (positional arguments) 和關鍵字參數。如示例,你可以將位置參數用作關鍵字參數:
~~~
{{ foo(20, y=21) }} -> 20, 21, 5, 6
~~~
你還可以用位置參數來替換關鍵字參數:
~~~
{{ foo(5, 6, 7, 8) }} -> 5, 6, 7, 8
~~~
如下示例,你可以跳過 ("skip") 位置參數:
~~~
{{ foo(8, z=7) }} -> 8, , 7, 6
{# Loop through all the users #}
{% for user in users %}...{% endfor %}
{% for i in [1,2,3,4,5] -%}
{{ i }}
{%- endfor %}
~~~
上面準確的輸出為 "12345",`-%} `會去除標簽右側的空白字符,`{%-` 會去除標簽之前的空白字符。
## **運算 (Math)**
Nunjucks 支持運算 (但盡量少用,把邏輯放在代碼中),可使用以下操作符:
* Addition: +
* Subtraction: -
* Division: /
* Division and integer truncation: //
* Division remainder: %
* Multiplication: *
* Power: **
可以如下使用:
~~~
{{ 2 + 3 }} (outputs 5)
{{ 10/5 }} (outputs 2)
{{ numItems*2 }}
~~~
比較 (Comparisons)
* ==
* ===
* !=
* !==
* >
* >=
* <
* <=
Examples:
~~~
{%-` 會去除標簽之前的空白字符。
## 表達式
你可以使用和 javascript 一樣的字面量。
* Strings: `"How are you?"`, `'How are you?'`
* Numbers: `40`, `30.123`
* Arrays: `[1, 2, "array"]`
* Dicts: `{ one: 1, two: 2 }`
* Boolean: `true`, `false`
### 運算 (Math)
Nunjucks 支持運算 (但盡量少用,把邏輯放在代碼中),可使用以下操作符:
* Addition: `+`
* Subtraction: `-`
* Division: `/`
* Division and integer truncation: `//`
* Division remainder: `%`
* Multiplication: `*`
* Power: `**`
可以如下使用:
```jinja
{{ 2 + 3 }} (outputs 5)
{{ 10/5 }} (outputs 2)
{{ numItems*2 }}
~~~
## **比較 (Comparisons)**
* ==
* ===
* !=
* !==
* >
* >=
* <
* <=
Examples:
~~~
{% if numUsers < 5 %}...{% endif %}
{% if i == 0 %}...{% endif %}
~~~
## Logic
* and
* or
* not
* 可使用大括號來分組
Examples:
~~~
{% if users and showUsers %}...{% endif %}
{% if i == 0 and not hideFirst %}...{% endif %}
{% if (x < 5 or y < 5) and foo %}...{% endif %}
~~~
## **If 表達式**
和 javascript 的三元運算符 (ternary operator) 一樣,可使用 if 的內聯表達式:
~~~
{{ "true" if foo else "false" }}
~~~
當 foo 為 true 的時候最終輸出 "true" 否則為 "false",對于獲取默認值的時候非常有用:
~~~
{{ baz(foo if foo else "default") }}
~~~
函數調用 (Function Calls)
如果你傳入一個函數,則可以直接調用
~~~
{{ foo(1, 2, 3) }}
~~~
~~~
{{ /^foo.*/ }}
{{ /bar$/g }}
~~~
正則表達式所支持的標志如下。查閱Regex on MDN以獲取更多信息。
* g: 應用到全局
* i: 不區分大小寫
* m: 多行模式
* y: 粘性支持(sticky)
## **自動轉義 (Autoescaping)**
如果在環境變量中設置了 autoescaping,所有的輸出都會自動轉義,但可以使用 safe 過濾器,Nunjucks 就不會轉義了。
~~~
{{ foo }} // <span%gt;
{{ foo | safe }} // <span>
~~~
如果未開啟 autoescaping,所有的輸出都會如實輸出,但可以使用 escape 過濾器來轉義。
~~~
{{ foo }} // <span>
{{ foo | escape }} // <span>
~~~
## **全局函數 (Global Functions)**
以下為一些內置的全局函數
### **range([start], stop, [step])**
如果你需要遍歷固定范圍的數字可以使用 range,start (默認為 0) 為起始數字,stop 為結束數字,step 為間隔 (默認為 1)。
~~~
{% for i in range(0, 5) -%}
{{ i }},
{%- endfor %}
~~~
上面輸出 0,1,2,3,4.
### **cycler(item1, item2, ...itemN)**
cycler 可以循環調用你指定的一系列的值。
~~~
{% set cls = cycler("odd", "even") %}
{% for row in rows %}
<div class="{{ cls.next() }}">{{ row.name }}</div>
{% endfor %}
~~~
上面的例子中奇數行的 class 為 "odd",偶數行的 class 為 "even"。你可以使用current屬性來獲取當前項(在上面的例子中對應cls.current)。
### **joiner([separator])**
當合并多項的時候,希望在他們之間又分隔符 (像逗號),但又不希望第一項也輸出。joiner 將輸出分割符 (默認為 ",") 除了第一次調用。
~~~
{% set comma = joiner() %}
{% for tag in tags -%}
{{ comma() }} {{ tag }}
{%- endfor %}
~~~
如果 tags 為 ["food", "beer", "dessert"], 上面將輸出 food, beer, dessert。
### **default(value, default, [boolean])**
(簡寫為 d)
如果value全等于undefined則返回default,否則返回value。 如果boolean為true,則會在value為JavaScript中的假值時(比如:false, ""等)返回default。
在2.0版本中,這個過濾器的默認表現與以前有所不同。在之前的版本中,它會把boolean的默認值 設置為true,所以傳入任何假值都會返回default。在2.0中,默認只有值為undefined時會 返回default。如果你仍舊希望保持原來版本的表現的話,你可以給boolean傳入true,或是 直接使用value or default。
### **sort(arr, reverse, caseSens, attr)**
用JavaScript中的arr.sort函數排序arr。如果reverse為true,則會返回相反的 排序結果。默認狀態下排序不會區分大小寫,但你可以將caseSens設置為true來讓排序 區分大小寫。我們可以用attr來指定要比較的屬性。
### **striptags (value, [preserve_linebreaks])**
類似于jinja中的striptags. 如果preserve_linebreaks為false(同時也是默認值),則會移去SGML/XML標簽并用一個空格符 替換臨近的、連續的空白符號。如果preserve_linebreaks為true,則會嘗試保留臨近的空白符號。 如果你希望使用管道操作符進行類似于{{ text | striptags | nl2br }}這樣的操作時,你就會 需要用到后一種。否則你還是應該使用默認的用法。
### **dump (object)**
在一個對象上調用JSON.stringify,并將結果輸出到模板上。這在調試時很有用:{{ foo | dump }}。
- CmsWing概覽
- CmsWing是什么
- CmsWing能干啥
- 運行&部署
- 1.windows 運行 cmswing
- 2.Linux 運行 cmswing
- 3.使用 docker 部署
- 4.部署方式推薦
- 5.Nginx反向代理 并做動靜分離
- 配置
- 快速上手
- 首頁
- 后臺使用說明
- 內容
- 內容管理
- 欄目管理
- 分類信息
- 回收站
- 網站模版
- 電商
- 營銷推廣
- 訂單中心
- 支付與配送
- 財務管理
- 系統
- 用戶管理
- 用戶信息
- 權限管理
- 用戶行為
- 行為日志
- 系統設置
- 網站設置
- 模型管理
- 配置管理
- 菜單管理
- 導航管理
- 數據庫備份
- 微信
- 公眾號設置
- 群發消息
- 素材管理
- 微信用戶管理
- 自動回復
- 自定義菜單
- 擴展
- 項目結構
- 目錄結構
- 模型設計
- 插件設計
- 用戶行為設計
- 權限設計
- 文檔模型設計
- 下載模型設計
- 圖片模型設計
- 視頻模型設計
- 商城模型設計
- 欄目設計
- 分類信息設計
- 模板規則
- 模版標簽入門
- 模塊類
- 模板語法規則
- 模版模型
- 模板調用方法
- 二次開發說明
- 命名規范與編碼規
- 數據庫字典
- 公共函數,Adapter,Middleware的使用規范
- 權限管理擴展說明
- 模型擴展開發說明
- 附錄
- 配置參考
- 函數庫參考
- Adapter參考
- Middleware參考
- FAQ
- Admin 管理
- 01.如何重置后臺admin 管理帳號密碼