express-8 Handlebars模板引擎(1)

简介

  • 使用JavaScript生成一些HTML
document.write('<h1>Please Don\'t Do This</h1>');
document.write('<p><span class="code">document.write</span> is naughty,\n');
document.write('and should be avoided at all costs.</p>');
document.write('<p>Today\'s date is ' + new Date() + '.</p>');

问题出如今这里:切换上下文环境是困难的。若是你写了大量的JavaSctipt,混合在HTML中会引发麻烦和混乱; 由JavaScript生成的HTML充满了问题:html

  • 必须不断地考虑哪些字符须要转义以及如何转义。
  • 使用JavaScript来生成那些自身包含JavaScript代码的HTML会很快让你抓狂。
  • 一般会失去编辑器的语法高亮显示和其余方便的语言特性。
  • 很难发现格式不正确的HTML。
  • 很难直观地分析。
  • 很难让别人读懂你的代码。

模板解决了在目标语言中编写代码的问题,同时也让插入动态数据成为了可能; 只有在某些最简单的状况下才会使用JavaScript生成HTML。node

选择模板引擎

一些可供参考的准则: 参考推荐文章git

  • 性能: 但愿模板引擎尽量地快
  • 客户端、服务端或兼而有之: 大多数(但不是全部)模板引擎均可用于客户端和服务器端。若是须要在这两端都使用模板,推荐选择那些在两端都表现优秀的模板引擎。
  • 抽象: 让代码更可读(例如,在普通HTML文本中使用大括号)

Template-Engine-Choosergithub

Jade

doctype html                              <!DOCTYPE html>
html(lang="en")                         <html lang="en">
  head                                          <head>
    title= pageTitle                       <title>Jade Demo</title>
    script.                                       <script>
       if (foo) {                                    if (foo) {
          bar(1 + 5)                                 bar(1 + 5)
       }                                                 }
  body                                          </script>
                                                    <body>
    h1 Jade                                   <h1>Jade</h1>
    #container                              <div id="container">
      if youAreUsingJade
        p You are amazing             <p>You are amazing</p>
      else
        p Get on it!
      p.                                           <p>
       Jade is a terse and                      Jade is a terse and
       simple templating                       simple templating
       language with a                          language with a
       strong focus on                           strong focus on
       performance and                        performance and
       powerful features.                       powerful features.
                                                    </p>
                                                    </body>
                                                    </html>

Jade无疑是少打了不少字,由于再也不有尖括号和结束标记。取而代之,它依赖缩进和一些常识性规则,从而更容易表达出本身想要的。Jade具备一个额外的优点:理论上讲,当HTML自身发生改变时,你能够轻松地将Jade定位于HTML版本的最新版本,从而让你的内容更具“前瞻性”。express

Handlebars基础

理解模板引擎的关键在于context(上下文环境):当渲染一个模板时,便会传递给模板引擎一个对象,叫做上下文对象,它能让替换标识运行。npm

例如,若是上下文对象是{ name: 'Buttercup' },模板是<p>Hello, {{name}}!</p> ,则 {{name}}会被Buttercup替换。若是向模板中传递HTML文本会发生什么呢?例如,上下文换成{ name: '<b>Buttercup</b>' },使用以前的模板获得的结果将是<p>Hello,&lt;b&gt;Buttercup&lt;b&gt;</p>,这或许并非你想要的。要想解决这个问题,用三个大括号代替两个就能够了:{{{name}}}。

  • 注释: 区分Handlebars注释和HTML注释很重要。示例以下:
{{! super-secret comment }}
<!-- not-so-secret comment -->

假设这是一个服务器端模板,上面的super-secret comment将不会被传递到浏览器,然而若是用户查看HTML源文件,下面的not-so-secret comment就会被看到。数组

  • 块级表达式浏览器

    上下文对象:

{
      currency: {
             name: 'United States dollars',
             abbrev: 'USD',
      },
      tours: [
              { name: 'Hood River', price: '$99.95' },
              { name: 'Oregon Coast', price: '$159.95' },
      ],
      specialsUrl: '/january-specials',
      currencies: [ 'USD', 'GBP', 'BTC' ],
}

传递到以下模板:缓存

<ul>
       {{#each tours}}
              {{! I'm in a new block...and the context has changed }}
              <li>
                         {{name}} - {{price}}
                         {{#if ../currencies}}
                                ({{../../currency.abbrev}})
                         {{/if}}
              </li>
       {{/each}}
</ul>
{{#unless currencies}}
       <p>All prices in {{currency.name}}.</p>
{{/unless}}
{{#if specialsUrl}}
       {{! I'm in a new block...but the context hasn't changed (sortof) }}
       <p>Check out our <a href="{{specialsUrl}}">specials!</p>
{{else}}
       <p>Please check back often for specials.</p>
{{/if}}
<p>
       {{#each currencies}}
             <a href="#" class="currency">{{.}}</a>
       {{else}}
             Unfortunately, we currently only accept {{currency.name}}.
       {{/each}}
</p>
  • each辅助方法,这使咱们可以遍历一个数组; 在下级块中,若是想访问currency对象,就得使用../来访问上一级上下文。
  • if辅助方法:
    在Handlebars中,全部的块都会改变上下文,因此在if块中,会产生一个新的上下文......而这恰好是上一级上下文的副本。换句话说,在if或else块中,上下文与上一级上下文是相同的。可是当在一个each循环中使用if块时就有必要细究一下了。在{{#each tours}}循环体中,可使用../.访问上级上下文。不过,在{{#if ../currencies}}块中,又进入了一个新的上下文......因此要得到currency对象,就得使用../../.。第一个../得到产品的上下文,第二个得到最外层的上下文。这就会产生不少混乱,最简单的权宜之计就是在each块中避免使用if块。服务器

  • 在if和each块中都有一个可选的else块(对于each,若是数组中没有任何元素,else块就会执行)。咱们也用到了unless辅助方法,它基本上和if辅助方法是相反的:只有在参数为false时,它才会执行。

  • 最后要注意的一点是在{{#each currencies}}块中使用{{.}}。{{.}}指向当前上下文,在这个例子中,当前上下文只是咱们想打印出来的数组中的一个字符串。

访问当前上下文还有另一种独特的用法:它能够从当前上下文的属性中区分出辅助方法。例如,若是有一个辅助方法叫做foo,在当前上下文中有一个属性也叫做foo,则{{foo}}指向辅助方法,{{./foo}}指向属性。

服务器端模板

服务器端模板与客户端模板不一样,客户端模板可以经过查看HTML源文看到,而不会看到服务器端模板,或是用于最终生成HTML的上下文对象。

服务器端模板除了隐藏实现细节,还支持模板缓存,这对性能很重要。模板引擎会缓存已编译的模板(只有在模板发生改变的时候才会从新编译和从新缓存),这会改进模板视图的性能。默认状况下,视图缓存会在开发模式下禁用,在生产模式下启用。若是想显式地启用视图缓存,能够这样作:app.set('view cache', true)

Express支持Jade、EJS和JSHTML。因此须要添加一个node包,让Express提供Handlebars支持。

npm install --save express3-handlebars

而后就能够在Express中引入:

var handlebars = require('express3-handlebars').create({ defaultLayout: 'main' });
app.engine('handlebars', handlebars.engine);
app.set('view engine', 'handlebars');

express3-handlebars让Handlebars模板拥有了.handlebars扩展名。能够在建立express3-handlebats实例将扩展名改为一样常见的.hbs;默认模版仍是main.hbs

var exphbs = require('express3-handlebars');
app.engine('hbs', exphbs({extname: '.hbs'}));
app.set('view engine', 'hbs');
相关文章
相关标签/搜索