模板引擎

ZKWeb的模板系统使用了DotLiquid.
您可以先参考DotLiquid的文档: http://dotliquidmarkup.org

为什么不使用Razor

  • DotLiquid的模板不要求拥有基类等复杂的环境, 只需要传参数即可编译
  • DotLiquid的模板只编译成语法树而不是IL, 页面第一次打开速度远比Razor快
  • DotLiquid的文件系统容易扩展, ZKWeb中已实现了类似Django的透过式文件系统

在控制器中返回模板

这里以项目创建器创建的空白项目为例, 首先文件结构是这样的:

  • 插件文件夹
    • src 源代码
    • static 静态文件
      • hello.world.css
        • hello.css
      • hello.world.js
        • hello.js
    • templates 模板文件
      • hello.world
        • hello.html

控制器返回模板的代码如下:

[ExportMany]
public class HelloController : IController {
    [Action("/")]
    public IActionResult Index() {
        // 第一个参数是模板路径, 第二个参数是传给模板的参数
        return new TemplateResult("hello.world/hello.html", new { text = "World" });
    }
}

模板hello.html的内容如下:

<!DOCTYPE html>
<html>
<head>
    <title>Hello</title>
    <link href="/static/hello.world.css/hello.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <h1>Hello {{ text }}!</h1>
    <hr />
    <div>
        <p>If you're seeing this, that mean you didn't use default plugin collections.</p>
        <p>So this is an empty project.</p>
        <p>You can open src\Controllers\HelloController.cs and add something to it.</p>
    </div>
    <script src="/static/hello.world.js/hello.js" type="text/javascript"></script>
</body>
</html> 

我们可以看到模板中有{{ text }}用于绑定传入的参数, 这个就是最简单的例子了.

您可能会奇怪为什么需要hello.world, hello.world.js, hello.world.css这些文件夹,
这是因为在ZKWeb中资源文件的命名空间在各个插件中是共享的,
您可以参考插件系统中对透过式文件系统的介绍.

模板的语法

变量

{{ }}可以用于描画变量或者常量到所在的位置:

Hello {{ name }}
Hello {{ user.name }}
Hello {{ 'tobi' }}

过滤器

{{ }}中使用|可以对绑定的值做出过滤.

Hello {{ 'tobi' | upcase }}
Hello tobi has {{ 'tobi' | size }} letters!
Hello {{ '*tobi*' | textilize | upcase }}
Hello {{ 'now' | date: "%Y %h" }}

标签

{% %}可以使用预定义的标签:

{% if user %}
  Hello {{ user.name }}
{% endif %}

{% if user.name == 'bob' and user.age > 45 %}
  Hello old bob
{% endif %}

更多的语法可以参考Liquid的官方文档.

安全绑值

使用DotLiquid绑值时并不是所有值都可以绑定,
内部会有一套安全机制让未经批准的值不能绑定到模板上.

需要允许绑定, 请让类型实现ILiquidizable, 或者标记类型为[LiquidType],
或者调用Template.RegisterSafeType(Type type, string[] allowedMembers)注册,
更详细的说明请查看这里.

DotLiquid内置的标签

DotLiquid内置了以下的标签:

assign

源代码: 点击查看

{% assign foo = 'monkey' %}

capture

源代码: 点击查看

{% capture heading %}
Monkeys!
{% endcapture %}

<h1>{{ heading }}</h1>

case

源代码: 点击查看

{% case condition %}{% when 1 %} its 1 {% when 2 %} its 2 {% endcase %}

comment

源代码: 点击查看

{%comment%} comment {%endcomment%}

continue

源代码: 点击查看

{% for i in array.items %}
  {% if i == 3 %}
    {% continue %}
  {% endif %}
  {{ i }}
{% endfor %}

cycle

源代码: 点击查看

{% for item in items %}
  <div class="{% cycle 'red', 'green', 'blue' %}">{{ item }}</div>
{% endfor %}

extend

源代码: 点击查看

用于继承模板, 具体例子请看上面代码中的注释.

for

源代码: 点击查看

{% for item in collection %}
  {{ forloop.index }}: {{ item.name }}
{% endfor %}

if

源代码: 点击查看

{% if user.admin %}
  Admin user!
{% else %}
  Not admin user
{% endif %}

include

源代码: 点击查看

{% include common.base/header.html %}

literal

源代码: 点击查看

{% literal %}{% if user = 'tobi' %}hi{% endif %}{% endliteral %}

raw

源代码: 点击查看

{% raw %}{% if user = 'tobi' %}hi{% endif %}{% endraw %}

unless

源代码: 点击查看

{% unless x < 0 %} x is greater than zero {% end %}

ZKWeb内置的标签

ZKWeb在DotLiquid的基础上内置了以下的标签:

area

参考动态内容.

{% area test_area %}

fetch

把指定路径的执行结果设置到变量, 适用于JsonResult和PlainResult.

{% fetch /api/login_info > login_info %}

html_lang

显示当前的请求的语言代号.

{% html_lang %}

raw_html

描画原始的内容, 不经过html编码.

{% assign variable = '<br/>' %}
{% raw_html variable %}

DotLiquid内置的过滤器

DotLiquid内置了以下的过滤器, 源代码可以查看这里.

size

{{ 'abc' | size }} == 3

slice

{{ 'abc' | slice 1,2 }} == bc

downcase

{{ 'Abc' | downcase }} == abc

url_encode

{{ '/' | url_encode }} == %2F

capitalize

{{ 'notThing' | url_encode }} == Notthing

escape, h(别名)

{{ '<strong>' | h }} == &lt;strong&gt;

truncate

{{ '1234567890' | truncate: 7 }} == 1234...

truncate_words

{{ 'one two three' | truncate_words: 2 }} == one two...

split

{{ 'This is a sentence' | split: ' ' }} == 列表对象

strip_html

{{ '<div>abc</div>' | strip_html }} == abc

currency

{{ 6.72 | currency }} == $6.72 (根据当前区域)

strip_newlines

{{ 'a\r\nb\r\nc' | strip_newlines }} == abc

join

{{ list_123 | join }} == 1 2 3

sort

{{ list_321 | sort | join }} == 1 2 3

map

{{ list_dogs | map: 'name' }} == 包含dog.name的列表

replace

{{ 'a a a' | replace: 'a', 'b' }} == b b b

replace_first

{{ 'a a a' | replace_first: 'a', 'b' }} == b a a

remove

{{ 'aabc' | remove: 'a' }} == bc

remove_first

{{ 'aabc' | remove_first: 'a' }} == abc

append

{{ 'a' | append: 'b' }} == ab

prepend

{{ 'a' | prepend: 'b' }} == ba

newline_to_br

{{ 'a\r\nb' | newline_to_br }} == a<br />\r\nb

date

{{ 'now' | date: 'MM/dd/yyyy' }} == 当前时间的MM/dd/yyyy格式

first

{{ list_123 | first }} == 1

last

{{ list_123 | last }} == 3

plus

{{ 1 | plus: 2 }} == 3

minus

{{ 1 | minus: 2 }} == -1

times

{{ 3 | times: 4 }}" == 12

round

{{ 1.234678 | round: 3 }} == 1.235

divided_by

{{ 15 | divided_by: 3 }} == 5

modulo

{{ 3 | modulo: 2 }} == 1

default

{{ not_exist | default: '123' }} == 123

ZKWeb内置的过滤器

ZKWeb在DotLiquid的基础上内置了以下的过滤器:

trans

翻译指定的文本,参考多语言.

{{ text | trans }}, {{ "fixed text" | trans }}

format

格式化字符串,最多可支持8个参数.

{{ "name is [0], age is [1]" | format: name, age }}

raw_html

描画原始的内容,不经过html编码.

{{ variable | raw_html }}

各个插件中还会有更多的自定义标签和过滤器, 请参考插件的文档说明.