简介###

  • 使用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. SQL Server order by语句学习回顾

    主要学习: 1.以指定的次序返回查询结果 2.按多个字段排序 3.按字串排序 4.处理排序空值 5.根据数据项的键排序 具体实例1---以指定的次序返回查询结果 n使用ORDER BY子句可以对结果集 ...

  2. 【leetcode】 Palindrome Partitioniong (middle) (*^__^*)

    Given a string s, partition s such that every substring of the partition is a palindrome. Return all ...

  3. 【leetcode】Remove Duplicates from Sorted List (easy)

    Given a sorted linked list, delete all duplicates such that each element appear only once. For examp ...

  4. GridView如何合并同类项

    /// <summary>     /// 合并GridView中某列相同信息的行(单元格)     /// </summary>     /// <param name ...

  5. css3属性flex弹性布局设置三列(四列)分布样式

    参考:阮一峰的网络日志 <!doctype html> <html lang="en"> <head> <meta charset=&qu ...

  6. iosTest

    NSString * url = @"http://192.168.0.11:8000/InterfaceApp/Login?UserName=15995858188&Passwor ...

  7. kmp

    #include <bits/stdc++.h> #define MAXN 100000 using namespace std; string a, b; int next[MAXN]; ...

  8. Swift - 让程序挂起后,能在后台继续运行任务

    1,程序的挂起和退出 由于iOS设备资源有限.当用户点击了home键,或者另一个应用程序启动了.那么原先那个程序便进入后台被挂起,不是退出,只是停止执行代码,同时它的内存被锁定.当应用程序恢复时,它会 ...

  9. Clr Via C#读书笔记---计算限制的异步操作

    线程池基础 1,线程的创建和销毁是一个昂贵的操作,线程调度以及上下文切换耗费时间和内存资源. 2,线程池是一个线程集合,供应你的用程序使用. 3,每个CLR有一个自己的线程池,线程池由CLR控制的所有 ...

  10. LeetCode之Binary Tree Level Order Traversal 层序遍历二叉树

    Binary Tree Level Order Traversal 题目描述: Given a binary tree, return the level order traversal of its ...