Mustache 模板






4.85/5 (6投票s)
Mustache 模板教程
引言
Mustache 是一个无逻辑的模板系统。Mustache 模板是一个文本字符串,其中包含文本和代表数据的标签。Mustache 渲染引擎接收一个模板,并使用给定的数据上下文中的数据替换标签。虽然 Mustache 类型模板在 AngularJS 等一些 JavaScript 库中使用,但它们本身也很有用。例如,它们非常适合处理 AJAX JSON 调用中的数据。收到 JSON 数据后,就可以将数据作为模板的上下文传递给 Mustache 引擎。渲染引擎的结果可以赋给 DOM 元素的 innerHTML 属性。
背景
用于 JavaScript 的 Mustache 模板系统及其文档在 GitHub 上:https://github.com/janl/mustache.js。所有不同语言的 Mustache 版本都在:https://mustache.github.io。一个类似的模板系统是 Handlebars,它在:https://handlebars.node.org.cn
模板定义
模板字符串非常简单。它是一个文本字符串,包含任何文本和由 {{expression}} 表示的 Mustache 标签,其中 expression 基本是一个简单的 JavaScript 表达式。Mustache 编译器接收模板字符串和一个 JavaScript 对象,并用对象中的数据替换标签。例如,像 "Album: {{title}}
" 这样的模板字符串,以及上下文数据对象:{title:"Blue Train"}
,将生成文本字符串 "Album: Blue Train"。然后,可以通过将 innerHTML 属性赋给 DOM 对象来将其放入网页。模板字符串可以包含 HTML 标签,因此当编译器渲染字符串时,您将获得一个可以插入网页的 HTML 标记块。这使得动态更改网页(例如,通过 AJAX 调用)变得很方便。
基本标签
Mustache 标签 {{ }}
包围了一个引用所提供上下文对象中数据的表达式。上下文数据对象的属性通过名称进行引用。标准的 JavaScript 点表示法用于上下文中的对象。
对于最简单的上下文对象,以下代码
Context = { title:"Sketches of Spain", artist:"Miles Davis" }; Template = "Title: {{title}} Artist: {{artist}}"; Result = Mustache.render(Template, Context);
结果是
Title: Sketches of Spain Artist: Miles Davis
如果数据包含 HTML 标记,请使用 {{{ }}}
,否则标记将被转义
Context = { title:"<u>Miles Davis With Sonny Rollins</u>", artist:"Miles Davis" }; Template = "Title: {{{title}}} Artist: {{artist}}"; Result = Mustache.render(Template, Context);
结果是
Title: <u>Miles Davis With Sonny Rollins</u> Artist: Miles Davis
如果上下文包含一个对象,请使用 JavaScript 点表示法。在下面的示例中,title 和 artist 是 album 的字段,因此标签中使用了点表示法
Context = { album: { title:"Blue Train", artist:"John Coltrane" } }; Template = "Title: {{album.title}} Artist: {{album.artist}}"; Result = Mustache.render(Template, Context);
这导致
Title: Blue Train Artist: John Coltrane
值 undefined、null、false 或 "" 不会被渲染。因此,在下面的示例中,title 和 artist 标签不会被渲染
Context = { title:null }; Template = "Album: Title:{{title}} Artist:{{artist}}"; document.getElementById("emptyvalue").innerHTML = Mustache.render(Template, Context);
结果是
Album: Title: Artist:
上下文中的对象可以用作“新的”默认上下文,方法是使用 section 标签。section 使用 {{#section}}
标签创建,并使用 {{/section}}
标签结束。在 section 中,名称引用标签中命名的对象。这类似于许多编程语言中使用的 using 或 with 语句。对于下面的示例,album 对象用作 section
Context = { album: { title:"The Healer", artist: "John Lee Hooker" } }; Template = "{{#album}}Title: {{title}} Artist:{{artist}}{{/album}}"; Result = Mustache.render(Template, Context);
结果是
Title: The Healer Artist: John Lee Hooker
虽然 Mustache 模板没有 if-then 语句,但仍然可以指定在值不存在时显示的文本。这是通过 {{^section}}
标签完成的。此 section 使用 {{/section}}
标签结束。如果 title 或 artist 缺失,以下模板将显示文本“unknown”
Context = { title:"Ball n Chain" }; Template = "Title:{{title}}{{^title}}Unknown{{/title}} Artist:{{artist}}{{^artist}}Unknown{{/artist}}"; Result = Mustache.render(Template, Context);
这导致
Title:Ball n Chain Artist:Unknown
重复值
虽然 Mustache 没有循环,但 section 可以发挥类似的作用。如果 section 名称是一个数组,则数组的每个值都会渲染 section 的内容。对于简单数据类型的数组,数组的元素使用点引用。如果数组为空,则不渲染 section。在下面的示例中,albums 数组由一个 section 渲染
Context = { albums: ["Little Creatures","Stop Making Sense"] }; Template = "{{#albums}}<li>{{.}}</li>{{/albums}}"; Result = Mustache.render(Template, Context);
这导致
<li>Little Creatures</li><li>Stop Making Sense</li>
如果数组元素是对象,则使用属性名
Context = { albums: [{title:"Go Bo Diddley"},{title:"Have Guitar Will Travel"}] }; Template = "{{#albums}}<li>{{title}}</li>{{/albums}}"; Result = Mustache.render(Template, Context);
结果是
<li>Go Bo Diddley</li><li>Have Guitar Will Travel</li>
上下文函数
上下文对象可以包含函数。它们通过函数名引用,不带 ()
。对于简单函数
Context = { description: function() { return "Transformer - Lou Reed"; } }; Template = "{{description}}"; Result = Mustache.render(Template, Context);
这导致
Transformer - Lou Reed
在函数内部,this 指的是当前正在渲染的 section。在 description 函数中,this 指的是 albums 数组的每个元素
Context = { albums: [{title: "Foggy Mountain Jamboree", artist: "The Foggy Mountain Boys"},{title:"Country Music", artist: "The Foggy Mountain Boys"}], description: function() { return this.title + " - " + this.artist; } }; Template = "{{#albums}}<li>{{description}}</li>{{/albums}}"; Result = Mustache.render(Template,Context );
结果是
<li>Foggy Mountain Jamboree - The Foggy Mountain Boys</li><li>Country Music - The Foggy Mountain Boys</li>
Section 函数
Section 名称可以是函数。这允许动态修改渲染结果。当遇到 section 函数时,该函数会用两个参数调用。第一个参数是 section 内容,第二个参数是 mustache 渲染函数。渲染函数可用于渲染 section 内容。渲染函数的上下文是包含 section 函数的上下文。返回值是渲染结果。最简单的用法是修改渲染结果的函数:(请注意,under 函数是一个返回实际 section 函数的函数)
Context = { title:"Where Did Our Love Go", artist: "The Supremes", under: function() { return function (TemplateText, MustacheRender) { return "<u>" + MustacheRender(TemplateText) + "</u>"; }; } }; Template = "{{#under}}{{title}}-{{artist}}{{/under}}"; Result = Mustache.render(Template,Context );
结果是
<u>Where Did Our Love Go-The Supremes</u>
该函数可以用于数组 section 内,因此可以为数组的每个元素测试渲染的文本。在以下代码中,supremes section 函数会给任何 Supremes 专辑添加下划线
Context = { supremes: function() { return function (TemplateText, MustacheRender) { var rendered = MustacheRender(TemplateText); if (rendered.indexOf("Supremes") >= 0) return "<u>" + rendered + "</u>"; else return rendered; }; }, albums: [{title: "I Hear a Symphony", artist: "The Supremes"},{title:"The Four Tops", artist: "The Four Tops"}] }; Template = "{{#albums}}<li>{{#supremes}}{{title}}-{{artist}}{{/supremes}}</li>{{/albums}}"; Result = Mustache.render(Template,Context );
结果是:
<li><u>I Hear a Symphony-The Supremes</u></li><li>The Four Tops-The Four Tops</li>
求值顺序
上下文名称的求值顺序有点棘手。标签中的名称从最内层上下文开始求值。如果在那里找不到名称,则检查父上下文,依此类推,直到找到名称为止。在下面的示例中,title 位于 albums 数组中,但 artist 位于父上下文中
Context = { artist: "Neil Young", albums: [{title: "Comes a Time"},{title: "After the Gold Rush"}] }; Template = "{{#albums}}<li>{{title}} - {{artist}}</li>{{/albums}}"; Result = Mustache.render(Template,Context );
结果是:
<li>Comes a Time - Neil Young</li><li>After the Gold Rush - Neil Young</li>
如果函数和属性具有相同的名称,则调用该函数,而忽略该属性。
Context = { description: "Comes a Time - Neil Young", description: function() {return "Harvest - Neil Young";} }; Template = "{{description}}"; Result = Mustache.render(Template,Context );
导致
Harvest - Neil Young
部分模板
部分模板是一种在一个模板中使用另一个模板的方式,有点像 include 指令。它们通过 {{> template}}
标签引用,并继承调用模板的上下文。部分模板在对象中传递给 render 函数。对象中的字段名是部分模板的名称。以下代码包含一个名为 FancyTitle 的部分模板,该模板为专辑标题应用红色
Context = { albums: [{title: "The Four Seasons", artist: "The Four Seasons"},{title:"Hal Miller and the Rays", artist: "The Four Seasons"}], }; var PartialTemplates = { FancyTitle : "<span style='color:red'>{{title}}</span>" }; Template = "{{#albums}}<div>{{> FancyTitle}} {{artist}}</div>{{/albums}}"; Result = Mustache.render(Template,Context,PartialTemplates);
这导致
<div><span style='color:red'>The Four Seasons</span> The Four Seasons</div><div><span style='color:red'>Hal Miller and the Rays</span> The Four Seasons</div>
使用 Mustache 函数
render 函数解析模板并将解析后的版本存储在内部缓存中。如果 render 函数再次看到模板,它将使用缓存的版本。parse 函数使引擎在不渲染的情况下解析并缓存模板。
Mustache.parse(Template); document.getElementById("functionvproperty").innerHTML = Mustache.render(Template,Context );