概念

Swig能干什么?如果Sass或者Less使得css可以编程,那么Swig和它们有些相似,它使得html标记语言变得可编程,支持变量,支持if else for控制语句。Swig模板文件以.swig为后缀,模板文件最终需要解析成html才能在网页上运行。

1
2
3
4
5
6
<h1>{{ pagename|title }}</h1>
<ul>
{% for author in authors %}
<li{% if loop.first %} class="first"{% endif %}>{{ author }}</li>
{% endfor %}
</ul>

安装

1
npm install swig-templates

注释

1
{# This is a comment.It will be fully stripped and ignored during parsing. #}

变量

1
2
3
4
5
6
7
{{ foo.bar }}
// 等价于,如果变量未定义,输出空字符。
{{ foo['bar'] }}

//变量后面加|可以使用过滤器,下面name后面的title就是过滤器
{{ name|title }} was born on {{ birthday|date('F jS, Y') }}
// Jane was born on July 6th, 1985

变量过滤器

  • add(value):使变量与value相加,可以转换为数值字符串会自动转换为数值。

  • addslashes:用 \ 转义字符串

  • capitalize:大写首字母

  • date(format[, tzOffset]):转换日期为指定格式

  • format:格式

  • tzOffset:时区

  • default(value):默认值(如果变量为undefined,null,false)

  • escape([type]):转义字符

  • 默认: &, <, >, “, ‘

    • js: &, <, >, “, ‘, =, -, ;
  • first:返回数组第一个值

  • join(glue):同[].join

  • json_encode([indent]):类似JSON.stringify, indent为缩进空格数

  • last:返回数组最后一个值

  • length:返回变量的length,如果是object,返回key的数量

  • lower:同’’.toLowerCase()

  • raw:指定输入不会被转义

  • replace(search, replace[, flags]):同’’.replace

  • reverse:翻转数组

  • striptags:去除html/xml标签

  • title:大写首字母

  • uniq:数组去重

  • upper:同’’.toUpperCase

  • url_encode:同encodeURIComponent

  • url_decode:同decodeURIComponemt

内置标签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//extends
{% extends "_layout.swig" %}

//include
{% include "../_partial/comments.swig" %}
//你可以标记 ignore missing,这样如果模板不存在,也不会抛出错误
{% include "foobar.html" ignore missing %}
//本地声明的上下文变量,默认情况不会传递给包含的模板。例如以下情况,inc.html 无法得到 foo 和 bar
{% set foo = "bar" %}
{% include "inc.html" %}
{% for bar in thing %}
{% include "inc.html" %}
{% endfor %}
//如果想把本地声明的变量引入到包含的模板种,可以使用 with 参数来把后面的对象创建到包含模板的上下文中
{% set foo = { bar: "baz" } %}
{% include "inc.html" with foo %}
{% for bar in thing %}
{% include "inc.html" with bar %}
{% endfor %}
//如果当前上下文中 foo 和 bar 可用,下面的情况中,只有 foo 会被 inc.html 定义,only 必须作为最后一个参数,放在其他位置会被忽略
{% include "inc.html" with foo only %}

//for
{% for x in y %}
{% if loop.first %}<ul>{% endif %}
<li>{{ loop.index }} - {{ loop.key }}: {{ x }}</li>
{% if loop.last %}</ul>{% endif %}
{% endfor %}
//在 for 标签里使用 else
{% for person in people %}
{{ person }}
{% else %}
There are no people yet!
{% endfor %}

//if
{% if x %}{% endif %}
{% if !x %}{% endif %}
{% if not x %}{% endif %}
{% if x and y %}{% endif %}
{% if x && y %}{% endif %}
{% if x or y %}{% endif %}
{% if x || y %}{% endif %}
{% if x || (y && z) %}{% endif %}
{% if x [operator] y %}
Operators: ==, !=, <, <=, >, >=, ===, !==
{% endif %}
{% if x == 'five' %}
The operands can be also be string or number literals
{% endif %}
{% if x|length === 3 %}
You can use filters on any operand in the statement.
{% endif %}
{% if x in y %}
If x is a value that is present in y, this will return true.
{% endif %}

//else 和 else if
{% if foo %}
Some content.
{% else if "foo" in bar %}
Content if the array `bar` has "foo" in it.
{% else %}
Fallback content.
{% endif %}

//autoescape
//假如
some_html_output = '<p>Hello "you" & \'them\'</p>';
//然后
{% autoescape false %}
{{ some_html_output }}
{% endautoescape %}
{% autoescape true %}
{{ some_html_output }}
{% endautoescape %}
{% autoescape true "js" %}
{{ some_html_output }}
{% endautoescape %}
//输出
<p>Hello "you" & 'them'</p>
&lt;p&gt;Hello &quot;you&quot; &amp; &#39;them&#39; &lt;/p&gt;
\u003Cp\u003EHello \u0022you\u0022 & \u0027them\u0027\u003C\u005Cp\u003E

//set
{% set foo = [0, 1, 2, 3, 4, 5] %} {% for num in foo %}
<li>{{ num }}</li>
{% endfor %}

//macro
//比如
{% macro input type name id label value error %}
<label for="{{ name }}">{{ label }}</label>
<input type="{{ type }}" name="{{ name }}" id="{{ id }}" value="{{ value }}"{% if error %} class="error"{% endif %}>
{% endmacro %}
//然后像下面使用
<div>
{{ input("text", "fname", "fname", "First Name", fname.value, fname.errors) }}
</div>
<div>
{{ input("text", "lname", "lname", "Last Name", lname.value, lname.errors) }}
</div>
//输出如下
<div>
<label for="fname">First Name</label>
<input type="text" name="fname" id="fname" value="Paul">
</div>
<div>
<label for="lname">Last Name</label>
<input type="text" name="lname" id="lname" value="" class="error">
</div>

//import
{% import 'formmacros.html' as form %}
{# this will run the input macro #}
{{ form.input("text", "name") }}
{# this, however, will NOT output anything because the macro is scoped to the "form" object: #}
{{ input("text", "name") }}

//filter
{% filter uppercase %}
oh hi, {{ name }}
{% endfilter %}
{% filter replace "." "!" "g" %}
Hi. My name is Paul.
{% endfilter %}
//输出
OH HI, PAUL Hi! My name is Paul!

//spaceless
{% spaceless %}
{% for num in foo %}
<li>{{ loop.index }}</li>
{% endfor %}
{% endspaceless %}
输出
<li>1</li><li>2</li><li>3</li>
  • extends:使当前模板继承父模板,必须在文件最前

    • 参数file:父模板相对模板 root 的相对路径
  • block:定义一个块,使之可以被继承的模板重写,或者重写父模板的同名块,参数name:块的名字,必须以字母数字下划线开头

  • parent:将父模板中同名块注入当前块中

  • include:包含一个模板到当前位置,这个模板将使用当前上下文,也就是嵌入另一个文件的内容

    • 参数file: 包含模板相对模板 root 的相对路径
    • 参数ignore missing:包含模板不存在也不会报错
    • 参数with x:设置 x 至根上下文对象以传递给模板生成。必须是一个键值对
    • 参数only:限制模板上下文中用 with x 定义的参数
  • import:允许引入另一个模板的宏进入当前上下文

    • 参数file:引入模板相对模板 root 的相对路径
    • 参数as:语法标记 var: 分配给宏的可访问上下文对象
  • for:遍历对象和数组,以下是特殊的循环变量

    • 参数x:当前循环迭代名,参数in:语法标记,参数y:可迭代对象。可以使用过滤器修改

    • loop.index:当前循环的索引(1开始)

    • loop.index0:当前循环的索引(0开始)

    • loop.revindex:当前循环从结尾开始的索引(1开始)

    • loop.revindex0:当前循环从结尾开始的索引(0开始)

    • loop.key:如果迭代是对象,是当前循环的键,否则同 loop.index

    • loop.first:如果是第一个值返回 true

    • loop.last:如果是最后一个值返回 true

    • loop.cycle:一个帮助函数,以指定的参数作为周期

  • if:条件语句

    • 参数:接受任何有效的 JavaScript 条件语句,以及一些其他人类可读语法
  • autoescape:改变当前变量的自动转义行为

    • 参数on:当前内容是否转义
    • 参数type:转义类型,js 或者 html,默认 html
  • set:设置一个变量,在当前上下文中复用

    • 参数name:变量名
    • 参数=:语法标记
    • 参数value:变量值
  • macro:创建自定义可服用的代码段

    • 参数…: 用户定义
  • filter:对整个块应用过滤器

    • 参数filter_name: 过滤器名字
    • 参数… : 若干传给过滤器的参数 父模板相对模板 root 的相对路径
  • spaceless:尝试移除html标签间的空格

模板继承

Swig 使用 extends 和 block 来实现模板继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//layout.html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>{% block title %}My Site{% endblock %}</title>
{% block head %}
<link rel="stylesheet" href="main.css">
{% endblock %}
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>

//index.html
{% extends 'layout.html' %}
{% block title %}My Page{% endblock %}
{% block head %}
{% parent %}
<link rel="stylesheet" href="custom.css">
{% endblock %}
{% block content %}
<p>This is just an awesome page.</p>
{% endblock %}