英语原文共 17 页,剩余内容已隐藏,支付完成后下载完整资料
Handlebars模板引擎
如果你没用过模板,或者根本不知道模板是什么,那它就是你将要从这本书中获得的最重要的东西。如果你是一个PHP 后端开发者,可能会认为 PHP 是第一批模板语言之一这根 本没什么大惊小怪的。几乎所有的主流开发语言都为了 Web 开发而增加了模板支持。目前 有所不同的是“模板引擎”与开发语言已经解耦。典型的例子是 Mustache,它是一个极受欢迎的、独立于开发语言的模板引擎。
那么到底什么是模板?让我们首先看看模板不是什么,我们以最明显也最直接的方式用一 种语言生成另外一种语言(具体来说,我们会使用 JavaScript 生成一些 HTML):
之所以称之为“明显”的唯一的原因也许是,这是一直被教导的编程方式:
10 PRINT 'Hello world!'
在命令式语言中,我们习惯于说“做这个,做那个,然后做另外的”。对于有些事情,这 种方法是可行的。如果你有一段 500 行的 JavaScript 代码,执行的是一个复杂计算,然后 返回一个数值,并且每一步都是依赖于上一步的,这并不会有什么问题。但如果是另外 一种情况呢?假如你有一段 500 行的 HTML 代码和一段 3 行的 JavaScript 代码。写 500 遍 document.write 有意义吗?一点也没有。
事实上,问题出现在这里:切换上下文环境是困难的。如果你写了大量的 JavaSctipt,混合在 HTML 中会引起麻烦和混乱。另一种方法并不糟糕:我们已经习惯了在 lt;scriptgt; 块 中写 JavaScript,但希望你能了解这个差异:这仍然会有上下文切换的问题,你或者只写 HTML,或者只在 lt;scriptgt; 块中写 JavaScript。由 JavaScript 生成的 HTML 充满了问题:
1.你必须不断地考虑哪些字符需要转义以及如何转义。
2.使用 JavaScript 来生成那些自身包含 JavaScript 代码的 HTML 会很快让你抓狂。
3.你通常会失去编辑器的语法高亮显示和其他方便的语言特性。
4.很难发现格式不正确的 HTML。
5.很难直观地分析。
6.很难让别人读懂你的代码。
模板解决了在目标语言中编写代码的问题,同时也让插入动态数据成为了可能。用 Mustache 模板将之前的例子重写:
现在我们要做的就是给 {{today}} 赋值,这就是模板语言的核心。
7.1 唯一一条绝对规则1
我并不是说一定不能在 JavaScript 中写 HTML,只是你应该尽量避免这么做。尤其要感谢 像 jQuery 这样的类库,它让前端代码变得更加优美。例如,这样做我并不会有意见:
$(#39;#error#39;).html(#39;Something lt;bgt;very badlt;/bgt; happened!#39;);
然而,如果最终变成这样:
也许就到了使用模板的时候了。重点是,我建议你在选择使用 HTML 字符串还是使用模 板时做出最佳判断。我宁可使用模板,不管怎样,只有在某些最简单的情况下才会使用 JavaScript 生成 HTML。
7.2 选择模板引擎
在 Node 的世界里,有许多模板引擎可供选择,那么如何挑选呢?这是个复杂的问题,而且大多取决于你的需求。下面是一些可供参考的准则。
1.性能
显然,你希望模板引擎尽可能地快。任何时候你都不会希望网站被拖慢。
2.客户端、服务端或兼而有之?
大多数(但不是所有)模板引擎都可用于客户端和服务器端。如果你需要在这两端都使 用模板(并且你确实会这样做),我推荐你选择那些在两端都表现优秀的模板引擎。
3.抽象
你想让代码更可读(例如,在普通 HTML 文本中使用大括号),或者你私下里厌恶 HTML 已久,希望有什么东西能把你从那些尖括号中拯救出来?模板(尤其是服务器 端模板)在这里为你提供了一些选择。
这些只是在选择模板语言时较为突出的准则。如果你想要了解关于这一主题更详细的 讨论,我强烈推荐你看看 Veena Basavaraj 的博客文章(http://engineering.linkedin.com/frontend/client-side-templating-throwdown-mustache-handlebars-dustjs-and-more), 那 里 有 她 为 LinkedIn 选择模板引擎时的相关准则。
LinkedIn 选择的是 Dust(http://akdubya.github.io/dustjs/),但是 Handlebars(http://handlebarsjs. com/)也入围了,后者是我首选的模板引擎,并且接下来也要在本书中使用。
Express 允许使用你想要的任何一个模板引擎,所以,如果你并不喜欢 Handlebars,可以轻 松地将它换掉。如果你想试试的话,可以使用这个有趣并且实用的工具:Template-EngineChooser(http://garann.github.io/template-chooser)。
7.3 Jade:不走寻常路
在大多数模板引擎还在以 HTML 为中心的时候,Jade 就以抽象 HTML 细节而引人注目。 同样值得注意的是,Jade 是 TJ Holowaychuk 的设想,他也是为我们带来 Express 的人。那 Jade 和 Express 可以很好地结合也就不足为奇了。Jade 采用的方式是难能可贵的,其核心 就是声称 HTML 是一种手写的模糊、枯燥的语言。让我们看看 Jade 模板是什么样的,同 时也看看它输出的 HTML(取自 Jade 主页 http://jade-lang.com/,为适应此书格式稍作 修改):
Jade 无疑是少打了很多字,因为不再有尖括号和结束标记。取而代之,它依赖缩进和一些 常识性规则,从而更容易表达出自己想要的。Jade 具有一个额外的优势:理论上讲,当 HTML 自身发生改变时,你可以轻松地将 Jade 定位于 HTML 版本的最新版本,从而让你 的内容更具“前瞻性”。
尽管我赞赏 Jade 的理念和优雅的执行,但是我发现,我并不想让 HTML 过于抽象。作为 一个 Web 开发者,HTML 是核心,如果代价是尖括号从我的键盘上磨损掉,那也没关系。 大部分前端开发人员的感受都如我所述,也许世界还没有准备好接受 Jadehellip;hellip;
从这里开始,我们要与 Jade 分道扬镳,在本书中你不会再见到它。然而,如果抽象概念很 吸引你,并且你确定在 Express 中使用 Jade 没有问题,还有很多资料可以帮助你。
7.4 Handlebars基础
Handlebars 是另一个流行的模板引擎 Mustache 的扩展。我推荐 Handlebars,是因为它简 单的 JavaScript 集成(前端和后端)和容易掌握的语法。对我来说,它实现了所有的平 衡,也是本书中要关注的。尽管我们正在讨论的概念是适用于其他模板的,但如果你觉得 Handlebars 不能激发你的想象力,可以去尝试其他不一样的模板引擎。
理解模板引擎的关键在于 context(上下文环境)。当你渲染一个模板时,便会传递给模板 引擎一个对象,叫作上下文对象,它能让替换标识运行。
例如,如果上下文对象是 { name: #39;Buttercup#39; },模板是 lt;pgt;Hello, {{name}}!lt;/pgt; ,则 {{name}} 会被 Buttercup 替换。如果向模板中传递 HTML 文本会发生什么呢?例如,上下 文换成 { name: #39;lt;bgt;Buttercuplt;/bgt;#39; },使用之前的模板得到的结果将是 lt;pgt;Hello,amp;lt;bamp;gt;Buttercupamp;lt;bamp;gt;lt;/pgt;,这或许并不是你想要的。要想解决这个问题,用三个大括号代 替两个就可以了:{{{name}}}。
虽然我们已经确定了应当避免在 JavaScript 中编写 HTML 代码,但是使 用三重大括号关闭 HTML 转义的功能具有一些重要用途。例如,如果用 WYSIWYG 编辑器建立了一个 CMS 系统,你大概会希望向视图层传递 HTML 文本是可行的。此外,能够脱离 HTML 转义渲染上下文属性对于布 局和章节是很重要的,这一点我们不久就会了解到。
在图 7-1 中,我们可以看到 Handlebars 引擎是怎样使用上下文(用椭圆表示)结合模板渲 染 HTML 的。
7.4.1 注释
Handlebars 的注释看起来像 {{! comment goes here }}。懂得如何区分 Handlebars 注释和 HTML 注释很重要。示例如下:
{{! super-secret comment }} lt;!-- not-so-secret comment --gt;
假设这是一个服务器端模板,上面的 super-secret comment 将不会被传递到浏览器,然而 如果用户查看 HTML 源文件,下面的 not-so-secret comment 就会被看到。你应该会喜欢 Handlebars 注释那些需要显示实现细节的地方,或者是你不想暴露出来的其他任何东西。
7.4.2 块级表达式
当你考虑块级表达式(block)的时候,事情就开始变得复杂了。块级表达式提供了流程控 制、条件执行和可扩展性。看一下下面的上下文对象:
现在让我们将上下文对象传递到如下模板:
这个模板很复杂,所以让我们分解一下。它开始于 each 辅助方法,这使我们能够遍历一个 数组。理解 {{#each tours}} 和 {{/each tours}} 之间的东西很重要,这涉及上下文切换。 第一次循环,上下文变成了 { name: #39;Hood River#39;, price: #39;$99.95#39; },第二次则变成了 { name: #39;Oregon Coast#39;, price: #39;$159.95#39; }。所以在这个块里面,我们可以看到 {{name}} 和 {{price}}。然而,如果你想访问 currency 对象,就得使用 ../ 来访问上一级上下文。
如果上下文属性本身就是一个对象,我们可以直截了当地访问它的属性,比如 {{currency. name}}。
if 辅助方法有些特殊,也有点让人困惑。在 Handlebars 中,所有的块都会改变上下文,所 以在 if 块中,会产生一个新的上下文hellip;hellip;而这刚好是上一级上下文的副本。换句话说, 在 if 或 else 块中,上下文与上一级上下文是相同的。上述实现细节通常是显而易见的, 但是当你在一个 each 循环中使用 if 块时就有必要细究一下了。在 {{#each tours}} 循环 体中,可以使用 ../. 访问上级上下文。不过,在 {{#if ../currencies}} 块中,又进入了 一个新的上下文hellip;hellip;所以要获得 currency 对象,就得使用 ../../.。第一个 ../ 获得产品 的上下文,第二个获得最外层的上下文。这就会产生很多混乱,最简单的权宜之计就是在 each 块中避免使用 if 块。
在 if 和 each 块中都有一个可选的 else 块(对于 each,如果数组中没有任何元素,else 块就会执行) 。我们也用到了 unless 辅助方法,它基本上和 if 辅助方法是相反的:只有在 参数为 false 时,它才会执行。
在这个模板中,最后要注意的一点是在 {{#each currencies}} 块中使用 {{.}}。{{.}} 指向 当前上下文,在这个例子中,当前上下文只是我们想打印出来的数组中的一个字符串。
访问当前上下文还有另外一种独特的用法:它可以从当前上下文的属性中区 分出辅助方法(我们很快就会学到)。例如,如果有一个辅助方法叫作 foo, 在当前上下文中有一个属性也叫作 foo,则 {{foo}} 指向辅助方法,{{./ foo}} 指向属性。
7.4.3 服务器端模板
服务器端模板会在 HTML 发送到客户端之前渲染它。服务器端模板与客户端模板不同,客 户端模板能够被懂得如何查看 HTML 源文件的富有好奇心的用户看到,而你的用户将不会 看到服务器端模板,或是用于最终生成 HTML 的上下文对象。
服务器端模板除了隐藏实现细节,还支持模板缓存,这对性能很重要。模板引擎会缓存已 编译的模板(只有在模板发生改变的时候才会重新编译和重新缓存),这会改进模板视图 的性能。默认情况下,视图缓存会在开发模式下禁用,在生产模式下启用。如果想显式地 启用视图缓存,可以这样做:app.set(#39;view cache#39;, true);。
Express 支 持 Jade、EJS 和 JSHTML。 我 们 已 经 讨 论 过 Jade 了, 而 且 我 觉 得 EJS 和 JSHTML 也不值得推荐(在我看来,在语法上做得还不够)。所以我们需要添加一个 node 包,让 Express 提供 Handlebars 支持。
npm install --save express3-handlebars
<p
全文共10081字,剩余内容已隐藏,支付完成后下载完整资料</p
资料编号:[15169],资料为PDF文档或Word文档,PDF文档可免费转换为Word
以上是毕业论文外文翻译,课题毕业论文、任务书、文献综述、开题报告、程序设计、图纸设计等资料可联系客服协助查找。