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生成HTML。node
一些可供参考的准则: 参考推荐文章git
Template-Engine-Choosergithub
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
理解模板引擎的关键在于context(上下文环境):当渲染一个模板时,便会传递给模板引擎一个对象,叫做上下文对象,它能让替换标识运行。npm
例如,若是上下文对象是{ name: 'Buttercup' },模板是<p>Hello, {{name}}!</p> ,则 {{name}}会被Buttercup替换。若是向模板中传递HTML文本会发生什么呢?例如,上下文换成{ name: '<b>Buttercup</b>' },使用以前的模板获得的结果将是<p>Hello,<b>Buttercup<b></p>,这或许并非你想要的。要想解决这个问题,用三个大括号代替两个就能够了:{{{name}}}。
{{! 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');