Handlebars是一个Javascript模板引擎,能让你轻松高效的编写语义化模板,它是Mustache模板引擎的一个扩展,Handlebars和Mustache都是弱逻辑的模板(logic-less template)引擎,能将Web前端的视图和数据分离,降低两者之间耦合。
  Handlebars的特点是一切都是表达式,没有操作数据的API,不污染HTML标签,和DeDeCMSWordPress模板类似,因此能很方便的与其他前端JS库(例如jQuery)混用,并且编写简单,易于扩展。Handlebars支持的浏览器及运行环境有:Internet Explorer 6+、Google Chrome、Firefox、Safari 5+、Opera 11+以及Node.js。Handlebars是Ember.js的默认模板引擎,同时也是基于Node.js的框架Clouda+Meteor的默认模板引擎。

下载

  可以在HandleBars的官方网站下载它的js文件,然后将其加入到你的项目中。如果你的Web项目中已经有一个名为js的文件夹专门放置JavaScript文件,这个位置就是极好的选择。下面的例子在WebStorm中的项目结构如下图所示。

JavaScript模板引擎初探 - HandleBars_模板引擎

用法

  首先在项目中引入HandleBars和jQuery的外部JavaScript文件,注意jQuery不是必须的,但是你必须承认它是一个非常优秀的JavaScript库,它兑现了“写得更少,做得更多”(Write Less, Do More)的承诺,使用jQuery提供的强大的选择器以及它对DOM和Ajax操作的封装还是能省不少事。所以,在下面的项目中我将HandleBars和jQuery都加入到了HTML页面中。

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>HandleBars Example</title>
</head>
<body>


    <script type="text/javascript" src="js/handlebars.js"></script>
    <script type="text/javascript" src="js/jquery.js"></script>
</body>
</html>

  HandleBars的模板和普通的HTML页面几乎没有区别,我们向上面的代码中加入一段内容。

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>HandleBars Example</title>
</head>
<body>
    <div>
        <h1>{{title}}</h1>
        <div>
            {{greeting}}
        </div>
    </div>

    <script type="text/javascript" src="js/handlebars.js"></script>
    <script type="text/javascript" src="js/jquery.js"></script>
</body>
</html>

  在上面的代码中,使用了HandleBars的表达式,HandleBars的表达式是写在{{ … }}中的代码。接下来我们将刚才添加的那段代码做成一个模板,做法很简单用一个<script>标签来包围那段代码。

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>HandleBars Example</title>
</head>
<body>
    <script id="foo" type="text/x-handlebars-template">
    <div>
        <h1>{{title}}</h1>
        <div>
            {{greeting}}
        </div>
    </div>
    </script>

    <script type="text/javascript" src="js/handlebars.js"></script>
    <script type="text/javascript" src="js/jquery.js"></script>
</body>
</html>

  接下来的工作就是用HandleBars来处理上面的模板,生成页面内容,表达式相当于是模板中的占位符,它会被相应的值替换掉,替换表达式的值可以用JSON方式来书写,代码如下所示。

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>HandleBars Example</title>
</head>
<body>
    <script id="foo" type="text/x-handlebars-template">
    <div>
        <h1>{{title}}</h1>
        <div>
            {{greeting}}
        </div>
    </div>
    </script>

    <script type="text/javascript" src="js/handlebars.js"></script>
    <script type="text/javascript" src="js/jquery.js"></script>

    <script type="text/javascript">
        var templateSection = $("#foo");   // 获得ID为foo的元素(模板代码段)的jQuery对象

        var sourceCode = templateSection.html();    // 获得模板段的HTML代码
        var template = Handlebars.compile(sourceCode);  // 用Handlebars的compile对模板进行编译

        var context = {title:"Hello, world!", greeting:"这是一个使用HandleBars的简单例子"};    // 用JSON保存数据
        var targetCode = template(context); // 将模板中的占位符替换成相应的数据得到最终的HTML代码

        templateSection.replaceWith(targetCode);    // 将原来的模板段替换成最终的HTML代码
    </script>
</body>
</html>

  需要注意的是,如果替换占位符的字符串中包含实体替换符(如:版权所有©、货币符号¥、右尖括号>),那么在书写HandleBars的表达式时应当用{{{ … }}},可以试一试下面的代码。

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>HandleBars Example</title>
</head>
<body>
    <script id="foo" type="text/x-handlebars-template">
    <div>
         <!-- 注意这里表达式的写法 -->
        <h1>{{{title}}}</h1>
        <div>
            {{greeting}}
        </div>
    </div>
    </script>

    <script type="text/javascript" src="js/handlebars.js"></script>
    <script type="text/javascript" src="js/jquery.js"></script>

    <script type="text/javascript">
        var templateSection = $("#foo");

        var sourceCode = templateSection.html();
        var template = Handlebars.compile(sourceCode);

        var context = {title:"Hello, world! >>", greeting:"这是一个使用HandleBars的简单例子"};   // 注意字符串中有实体替换符
        var targetCode = template(context);

        templateSection.replaceWith(targetCode);
    </script>
</body>
</html>

  HandleBars最让人激动的特性应该是块表达式以及自定义帮助器(块表达式处理器),下面的例子演示了块表达式的使用。

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>HandleBars Example</title>
</head>
<body>
    <script id="foo" type="text/x-handlebars-template">
    <div>
        <h1>{{{title}}}</h1>
        <div>
            {{greeting}}
        </div>
    </div>
    <!-- 使用块表达式 -->
    {{#foreach persons}}
        {{name}}: {{age}}
    {{/foreach}}
    </script>

    <script type="text/javascript" src="js/handlebars.js"></script>
    <script type="text/javascript" src="js/jquery.js"></script>

    <script type="text/javascript">
        // 注册一个帮助器(块表达式处理器)
        Handlebars.registerHelper("foreach", function(items, options) {
            var out = "<ul>";
            for(var i = 0, len = items.length; i < len; ++i) {
                out += "<li>" + options.fn(items[i]) + "</li>";
            }
            return out + "</ul>";
        });

        var templateSection = $("#foo");

        var sourceCode = templateSection.html();
        var template = Handlebars.compile(sourceCode);

        var context = {
            title:"Hello, world! >>",
            greeting:"这是一个使用HandleBars的简单例子",
            persons: [
                {name:"Hao LUO", age:34},
                {name:"王大锤", age:25},
                {name:"张三丰", age:120}
            ]
        };
        var targetCode = template(context);

        templateSection.replaceWith(targetCode);
    </script>
</body>
</html>

  再看一个例子吧。

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>HandleBars Example</title>
</head>
<body>
    <script id="foo" type="text/x-handlebars-template">
    <div>
        <h1>{{{title}}}</h1>
        <div>
            {{greeting}}
        </div>
    </div>
    {{!-- 下面是一个块表达式 --}}
    {{#foreach persons}}
        {{f name}}{{t gender}}: {{age}}
    {{/foreach}}
    </script>

    <script type="text/javascript" src="js/handlebars.js"></script>
    <script type="text/javascript" src="js/jquery.js"></script>

    <script type="text/javascript">
        // 注册一个帮助器(块表达式处理器)
        Handlebars.registerHelper("foreach", function(items, options) {
            var out = "<ul>";
            for(var i = 0, len = items.length; i < len; ++i) {
                out += "<li>" + options.fn(items[i]) + "</li>";
            }
            return out + "</ul>";
        });

        // f帮助器从名字中取出姓氏
        Handlebars.registerHelper("f", function(name) {
             return name.charAt(0); // 假定都是中文姓名且都是单姓(只是一个小例子而已不要叫真是否合理)
        });

        // t帮助器根据性别输出先生或女士
        Handlebars.registerHelper("t", function(gender) {
            return gender ? "先生" : "女士";
        });

        var templateSection = $("#foo");

        var sourceCode = templateSection.html();
        var template = Handlebars.compile(sourceCode);

        var context = {
            title:"Hello, world! >>",
            greeting:"这是一个使用HandleBars的简单例子",
            persons: [
                {name:"骆昊", gender:true, age:34},
                {name:"王大锤", gender:false, age:25},
                {name:"张三丰", gender:true, age:120}
            ]
        };
        var targetCode = template(context);

        templateSection.replaceWith(targetCode);
    </script>
</body>
</html>

  运行效果如下图所示。

JavaScript模板引擎初探 - HandleBars_html_02

  当然,HandleBars已经内置了最常用的块处理器。

  • if:如果参数值是false、undefined、null、""、0或[],HandlerBars就不会渲染块表达式。代码如下所示:
<div class="entry">
    {{#if author}}
        <h1>{{firstName}} {{lastName}}</h1>
    {{/if}}
</div>

  也就是说,上面的代码在上下文中没有author定义的情况下,会产生下面的输出:

<div class="entry">
</div>
  • unless:作用与if正好相反。
  • each:可以对数组进行迭代。在迭代时还可以使用{{@index}}表示第几次循环,可以用{{@key}}表示对象的属性名。
<ul class="person_list">
    {{#each persons}}
        <li>{{this}}</li>
    {{/each}}
 </ul>

  上下文数据如下所示:

{ persons:["骆昊", "王大锤", "张三丰"] }

  更多的内容可以关注HandleBars的官方网站关于内置帮助器的内容。

  可以使用jQuery封装的Ajax函数从服务器获取JSON格式的上下文数据,代码如下所示:

$.getJSON("HelloServlet", {}, function(context) {
    var targetCode = template(context);
    templateSection.replaceWith(targetCode);
});

  HandleBars的官方网站还提供了HandleBars的参考手册