65.9K
CodeProject 正在变化。 阅读更多。
Home

Mustache 模板

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.85/5 (6投票s)

2015年6月11日

CPOL

5分钟阅读

viewsIcon

37257

downloadIcon

333

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 );
© . All rights reserved.