--- title: "Mustache 模板引擎中文文档" date: 2021-06-19T11:11:55+07:00 draft: false --- ### 前言 Mustache 是一个有趣的引擎,总会让人想起语言界的函数式编程。官网上有关于这个引擎每种语言的实现。实现这词很合适,因为 Mustache 是一个规范,一个标准定义,详细参看 [specs](https://github.com/mustache/spec)。 Mustache 引擎实际应用据我观察是不多的,但这并不能掩盖它的美感。 [Mustache](https://mustache.github.io/) 是一个无逻辑(logic-less)的模板引擎。源自于 google 的 [ctemplate](http://ctemplate.sourceforge.net/)。 ### 概要 一个示例 ```golang Hello {{name}} You have just won {{value}} dollars! {{#in_ca}} Well, {{taxed_value}} dollars, after taxes. {{/in_ca}} ``` 使用参数如下 ```json { "name": "Chris", "value": 10000, "taxed_value": 10000 - (10000 * 0.4), "in_ca": true } ``` 渲染输出如下 ```html Hello Chris You have just won 10000 dollars! Well, 6000.0 dollars, after taxes. ``` ### 简介 Mustache 可用于渲染 HTML,配置文件生成,源代码生成等所有场景。它的工作方式是使用 json 对象中的值替换/扩展模板中的 Tag。 之所以称之为“无逻辑”主要是因为 Mustache 不使用 if else 语句,不使用 for 循环。只有 Tag。有些 Tag 被替换为一个值,有的被替换为一系列值,有的则什么也不做,这取决于 Tag 的功能和渲染使用的参数。 ### Tag 类型 Tag 用双大括号来表示。 {{person}} 是一个 Tag,就像 {{#person}} 也是一个 Tag;这两者中,我们都是用 __person__ 作为 key,总共有以下几种 Tag. #### 变量 (Variables) 最基础的 tag 类型是变量类型。例如 {{name}} tag 是一个非常基本的变量类型,它会在当前的处理上下文中搜索 __name__ 这个 key,如果找不到,则会继续递归式地向上级上下文中搜索,如果直到顶级上下文也无法找到,则什么也不会渲染。 所有的变量类型默认都会转义 HTML 内容,如果想输出原始的 HTML 内容,需要使用三重大括号: {{{name}}}。 也可以使用 & 来表示非转义变量,例如 {{& name}},这在更改分隔符的情况下很有用。(详见 设置分隔符 部分) 通常,一个变量 tag 如果匹配不到会返回空字符串,这个特性可在各个 Mustache 实现库中更改(可配置)。例如 Ruby 版本的实现是在这种情况下抛出一个异常。 模板 ```golang * {{name}} * {{age}} * {{company}} * {{{company}}} ``` 参数: ```json { "name": "Chris", "company": "GitHub" } ``` 输出 ```html * Chris * * <b>GitHub</b> * GitHub ``` #### 段(Sections) 段类型渲染一个文本块一次或多次,取决于当前上下文中的对应 key 的值。段类型 Tag以 # 开始,以 / 结束。例如 {{#person}} 开始一个段 {{/person}} 结束。 段类型渲染行为取决于 key 的值,规则如下: 1. False 或 [] 如果 __person__ 这个 key 存在并且它的值是 false 或空列表,则段中的内容不会被渲染。 模板 ```golang Shown. {{#person}} Never shown! {{/person}} ``` 参数 ```json { "person": false } ``` 输出 ```html Shown. ``` 2. 非空列表 如果 __person__ 字段存在并且具有 non-false 值,则段中的内容会被渲染一次或多次。 如果值是非空列表,则段中的内容会使用列表中的每个元素渲染一次,每次渲染,当前元素就是它的上下文。可以使用段类型来处理集合。 模板 ```golang {{#repo}} {{name}} {{/repo}} ``` 参数 ```json { "repo": [ { "name": "resque" }, { "name": "hub" }, { "name": "rip" } ] } ``` 输出 ```html resque hub rip ``` 3. 函数 (Lambdas) 如果值是一个可调用对象,比如 function 或 lambda,则该对象会被调用,段中的内容会被作为参数以字面值的形式(不渲染)传入,{{tags}} 并不会被展开-一切交给 lambda。通过 lambda 可以实现过滤器和缓存。 模板 ```golang {{#wrapped}} {{name}} is awesome. {{/wrapped}} ``` 参数 ```json { "name": "Willy", "wrapped": function() { return function(text, render) { return "" + render(text) + "" } } } ``` 输出 ```html Willy is awesome. ``` 4. 非假值 如果值是一个非假值但不是一个列表,此值会被用作段内容的上下文进行一次渲染。 模板 ```golang {{#person?}} Hi {{name}}! {{/person?}} ``` 参数 ```json { "person?": { "name": "Jon" } } ``` 输出 ```html Hi Jon! ``` #### 倒置段 (Inverted Sections) 一个倒置段以 ^ 开始,以 / 结束。比如 {{^person}} 开始一个名为 __person__ 的倒置段,{{/person}} 结束。 段类型可以用来根据 key 的值来渲染段中内容一次或多次,倒置段类型则根据 key 的值来渲染段中内容最多一次: 当且仅当这个 key 不存在,值为 false 或为空列表。 模板 ```golang {{#repo}} {{name}} {{/repo}} {{^repo}} No repos :( {{/repo}} ``` 参数 ```json { "repo": [] } ``` 输出 ```html No repos :( ``` #### 注释 注释以感叹号开头,其中的内容会被忽略。比如模板 ```html