简介###

  • 使用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充满了问题:

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

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

选择模板引擎###

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

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

Template-Engine-Chooser

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版本的最新版本,从而让你的内容更具“前瞻性”。

Handlebars基础###

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

例如,如果上下文对象是{ 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');

express-8 Handlebars模板引擎(1)的更多相关文章

  1. 【转】在Express项目中使用Handlebars模板引擎

    原文:http://fraserxu.me/2013/09/12/Using-Handlebarsjs-with-Expressjs/ 最近在用Expressjs做一个项目,前后端都用它来完成.自己之 ...

  2. Handlebars模板引擎中的each嵌套及源码浅读

    若显示效果不佳,可移步到愚安的小窝 Handlebars模板引擎作为时下最流行的模板引擎之一,已然在开发中为我们提供了无数便利.作为一款无语义的模板引擎,Handlebars只提供极少的helper函 ...

  3. Express ( MiddleWare/中间件 路由 在 Express 中使用模板引擎 常用API

    A fast, un-opinionated, minimalist web framework for Node.js applications. In general, prefer simply ...

  4. Handlebars模板引擎之高阶

    Helpers 其实在Handlebars模板引擎之进阶我想说if else的功能的,可是由于这个功能在我的开发中我觉的鸡肋没啥用,就直接不用了. 因为if else只能进行简单判断,如果条件参数返回 ...

  5. handlebars模板引擎使用初探1

    谈到handlebars,我们不禁产生疑问,为什么要使用这样的一个工具呢?它究竟能为我们带来什么样的好处?如何使用它呢? 一.handlebars可以干什么? 首先,我们来看一个案例: 有这样的htm ...

  6. express-9 Handlebars模板引擎(2)

    视图和布局 视图通常表现为网站上的各个页面(它也可以表现为页面中AJAX局部加载的内容,或一封电子邮件,或页面上的任何东西).默认情况下,Express会在views子目录中查找视图.布局是一种特殊的 ...

  7. Handlebars 模板引擎之前后端用法

    前言 不知不觉间,居然已经这么久没有写博客了,坚持还真是世界上最难的事情啊. 不过我最近也没闲着,辞工换工.恋爱失恋.深圳北京都经历了一番,这有起有落的生活实在是太刺激了,就如拿着两把菜刀剁洋葱一样, ...

  8. express 4.x 模板引擎与express.static

    前提:要在express中使用模块引擎需要将要使用的模板引擎安装在本项目,当然,express也是要安装的.在下面实例中,我使用的模板引擎是pug(一起叫做jade) 我的目录结构如下: 根目录为st ...

  9. express中ejs模板引擎

    1.在 app.js 中通过以下两个语句设置了 引擎类型 和页面模板的位置: app.set('views', __dirname + '/views'); app.set('view engine' ...

随机推荐

  1. Quartz 使用

    public class IndexJob:IJob//此处必须实现 IJob接口 { /// <summary> /// 具体的任务 /// </summary> /// & ...

  2. 【Git】自定义Git

    来源:廖雪峰 让Git显示颜色 git config --global color.ui true 忽略特殊文件 有些文件有敏感信息,或者是自动生成的中间文件.不能或不必提交到git,可以用.giti ...

  3. October 10th 2016 Week 42nd Monday

    What makes life dreary is the want of motive. 没有了目标,生活便黯然无光. Motive and goal, are absolutely indispe ...

  4. js中我的注释规范

    模块功能描述说明: /** * ------------------------------------------------------------------ * 模块描述说明 * ------ ...

  5. Linux 压缩系列常用命令

    tar 命令: http://man.linuxde.net/tar zip 命令: http://man.linuxde.net/zip unzip 命令: http://man.linuxde.n ...

  6. 将前台json对象传入java后台

    前台json格式的数据如何传入后台 1. 将要传入后台的数据组装成JSON格式的字符串: var jsonStr = [{'name':'jim' , 'age':20} , {'name':'kin ...

  7. Page Object Model (Selenium, Python)

    时间 2015-06-15 00:11:56  Qxf2 blog 原文  http://qxf2.com/blog/page-object-model-selenium-python/ 主题 Sel ...

  8. set -x 跟踪脚本执行信息

    注意set -x其中"-"与"x"之间没有空格 [root@GitLab sh]# ./sx.sh heelo + a=heelo + echo heelo h ...

  9. 《CLR via C#》读书笔记(1)CLR执行模型

    1.1 释义 CLR 公共语音运行时 Common Language Runtime CTS 通用类型系统 Common Type System CTS.CLS是CLR的核心 CLS 通用语言规范 C ...

  10. Newtonsoft.Json(Json.Net)学习笔记-高级使用(转)

    1.忽略某些属性 2.默认值的处理 3.空值的处理 4.支持非公共成员 5.日期处理 6.自定义序列化的字段名称 7.动态决定属性是否序列化 8.枚举值的自定义格式化问题 9.自定义类型转换 10.全 ...