诗与远方

next主题的模板引擎swig语法介绍

next采用的模板引擎是swig,swig 是node端的一个优秀简洁的模板引擎,类似Python模板引擎Jinja,目前不仅在node端较为通用,相对于jade、ejs优秀,而且在浏览器端也可以很好地运行。

所以,要想能够对next有更多的了解,进行更加个性化的定制,最基础的还是先要了解和学习一下swig的语法知识,了解他的常用用法。

声明

因为此博客使用next框架的原因,swig也会渲染此页面中间的代码,导致出错,在经过多次尝试之后(爬坑),采取加空格的方式解决,即在原来的{{之间,{%增加一个空格来避免被渲染。

特性

  • 支持大多数主流浏览器。
  • 表达式兼容性好。
  • 面向对象的模板继承。
  • 将过滤器和转换应用到模板中的输出。
  • 可根据路劲渲染页面。
  • 支持页面复用。
  • 支持动态页面。
  • 可扩展、可定制。

安装

1
$ npm install swig --save

基本用法

swig有多种实现方式来编译和渲染模板

1
2
3
4
5
6
7
8
var swig = require('swig');
// Compile a file and store it, rendering it later
var tpl = swig.compileFile('/path/to/template.html');
console.log(tpl({ article: { title: 'Swig is fun!' } }));
// 直接渲染字符串模板
console.log(swig.render('{ % if foo % }Hooray!{ % endif % }', { locals: { foo: true } }));

变量

模板中的变量使用双大括号{ {} }来声明。例如

1
{ {a} }

属性

变量的属性可以使用.或者[ ]来访问,如下两个是等价的:

1
2
3
4
{ { foo.bar } }
// is equivalent to
{ { foo['bar'] } }

他遵循和javascript一样的原则,如果关键词中有-,则必须使用[]来访问属性,不能使用.

Bad!

1
{ { foo.chicken-tacos } }

Good!

1
{ { foo['chicken-tacos'] } }

未定义和空值

如果一个变量未定义或者是空值,在渲染的时候,将会在相应的位置输出一个空的字符串,而不会报异常。

过滤器

变量可以用特殊的链式结构进行修改过滤。

1
2
3
4
{ { name|title } } was born on { { birthday|date('F jS, Y') } }
// => Jane was born on July 6th, 1985

方法(函数)

变量也可以是 JavaScript functions. 值得注意的是,不管你的 autoescape设定是什么样的,方法都不会被 auto-escaped.

1
2
3
var locals = { mystuff: function mystuff() { return '<p>Things!</p>'; } };
swig.render('{ { mystuff() } }', { locals: locals });
// => <p>Things!</p>

If you want to enforce escaping output on functions, just pipe them to the escape filter.

1
2
{ { mystuff()|escape } }
// => <p>Things</p>

逻辑标签

Swig包含一些基本的可选的代码块,叫做标签,使用标签可以更好的控制模板的渲染输出。标签示例如下

1
2
3
4
5
6
7
8
{ % if foo % }bar{ % endif % }
// Create a list of people, only if there are items in the people array
{ % for person in people % }
{ % if loop.first % }<ol>{ % endif % }
<li>{ { person.name } }</li>
{ % if loop.last % }</ol>{ % endif % }
{ % endfor % }

其中{ % endif % }{ % endfor % }是结束标签,用于表明代码块的的结束。

1
2
3
4
5
6
7
8
{ % block tacos % }
//...
{ % endblock tacos % }
{ % block burritos % }
{ % if foo % }
// ...
{ % endif % } //the above will render if foo == true
{ % endblock burritos % }

更多关于tag的信息,请查看官方文档,这里挑几个重点的经常见到的说说。

block标签

用于声明一个代码块,继承的子模板中间可以改写或者拓展父模板中同名的代码块。也可查看#继承

例如

1
{ % block body % }...{ % endblock % }

if-else-endifif-elseif-endif标签

这个与java中的if功能类似,做条件判断时使用。满足条件的内容将会被输出。

1
2
3
{ % if x|lower === 'tacos' % }
You can use filters on any operand in the statement.
{ % endif % }
1
2
3
{ % if x in y % }
If x is a value that is present in y, this will return true.
{ % endif % }
1
2
3
4
5
6
7
8
{ % if false % }
Tacos
{ % elseif true % }
Burritos
{ % else % }
Churros
{ % endif % }
// => Burritos

extends 标签

使当前的模板继承一个父模板,这个标签必须位于模板的最前面。其他查看#继承

1
{ % extends "./layout.html" % }

for标签

用于遍历对象和数组时使用。

参数

NameType是否可选Default描述
keyliteralundefinedA shortcut to the index of the array or current key accessor.
variableliteralundefinedThe current value will be assigned to this variable name temporarily. The variable will be reset upon ending the for tag.
inliteralundefinedLiterally, “in”. This token is required.
objectobjectundefinedAn enumerable object that will be iterated over.

Returns

loop.index: The current iteration of the loop (1-indexed)

loop.index0: The current iteration of the loop (0-indexed)

loop.revindex: The number of iterations from the end of the loop (1-indexed)

loop.revindex0: The number of iterations from the end of the loop (0-indexed)

loop.key: If the iterator is an object, this will be the key of the current item, otherwise it will be the same as the loop.index.

loop.first: True if the current object is the first in the object or array.

loop.last: True if the current object is the last in the object or array.

示例

1
2
3
4
5
6
7
8
9
10
// obj = { one: 'hi', two: 'bye' };
{ % for x in obj % }
{ % if loop.first % }<ul>{ % endif % }
<li>{ { loop.index } } - { { loop.key } }: { { x } }</li>
{ % if loop.last % }</ul>{ % endif % }
{ % endfor % }
// => <ul>
// <li>1 - one: hi</li>
// <li>2 - two: bye</li>
// </ul>
1
2
3
4
5
6
7
8
// arr = [1, 2, 3]
// Reverse the array, shortcut the key/index to `key`
{ % for key, val in arr|reverse % }
{ { key } } -- { { val } }
{ % endfor % }
// => 0 -- 3
// 1 -- 2
// 2 -- 1

import

Source: lib/tags/import.js

允许你引入定义在别的文件当中的宏到你当前的模板文件当中。

The import tag is specifically designed for importing macros into your template with a specific context scope. This is very useful for keeping your macros from overriding template context that is being injected by your server-side page generation.

参数

NameTypeOptionalDefaultDescription
filestring orvarundefinedRelative path from the current template file to the file to import macros from.
asliteralundefinedLiterally, “as”.
varnameliteralundefinedLocal-accessible object name to assign the macros to.

示例

1
2
3
4
5
6
{ % import './formmacros.html' as form % }
{ { form.input("text", "name") } }
// => <input type="text" name="name">
{ % import "../shared/tags.html" as tags % }
{ { tags.stylesheet('global') } }
// => <link rel="stylesheet" href="/global.css">

注释

Comments注释在渲染时将会被忽略,他们在渲染之前就会移除,所以没人能看到你的注释,除非他们查看你的源代码。

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

空格控制符

模板中的任何空格都会被输出在最终生成的页面上。然而,你可以使用空格控制符来消除空格。

在tag的前面或者后面添加-来移除前面或者后面的空格。

1
2
3
4
// seq = [1, 2, 3, 4, 5]
{ % for item in seq -% }{ { item } }
{ %- endfor % }
// => 12345

注意 没有任何空格输出

继承

swig使用extends关键字来对模板进行继承

layout.html

1
2
3
4
5
6
7
8
9
10
11
12
13
<!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

1
2
3
4
5
6
7
8
9
{ % 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 % }d

模板index.html继承自layout.html,并且改写或者实现了其中的内容。

参考资料