Handlebars — JS 模板引擎笔记

前端2015-05-310 篇评论 JavaScript

如今的 MVC 设计模式,使得后台在视图和模型之间完成了分离。可是,前端 html 页面和数据的分离和整合却又遇到了麻烦。当页面大量使用 AJAX 时,整个前端页面的可维护性就变得很差了。原因有几点:

  1. 写在 js 字符串里的 html 文本(包括换行符)必须经过很多反斜线(\)转义;
  2. 大量的 js 语句穿插在 js 字符串里;
  3. 复杂功能较难实现

常常会出现类似的代码:

var anew = "\
  <div class=\"row card anews\" style=\"display:none\">\
    <div>\
      <div class=\"pic-head\"></div>\
      <h2 class=\"anews-title\">\
        <a href=\"#" + data[i].id + "\">"+data[i].title+"</a>\
      </h2>\
    </div>\
    <div class=\"anews-info\">\
        <span class=\"glyphicon glyphicon-pencil\" aria-hidden=\"true\"></span>\
        <a href=\"#\">"+ data[i].publicName +"</a>&nbsp;&nbsp;&nbsp;&nbsp;\
        <span class=\"glyphicon glyphicon-time\" aria-hidden=\"true\"></span>\
        "+ data[i].time +"&nbsp;&nbsp;&nbsp;&nbsp;\
        <span class=\"glyphicon glyphicon-eye-open\" aria-hidden=\"true\"></span>\
         ( "+ data[i].clickNum +" )&nbsp;&nbsp;&nbsp;&nbsp;\
        <span class=\"glyphicon glyphicon-edit\" aria-hidden=\"true\"></span>\
         ( "+ data[i].commentNum +" )&nbsp;&nbsp;&nbsp;&nbsp;\
    </div>\
    <div class=\"anews-summary\">";
    if(data[i].picUrl != null) {
      anew += "<img class=\"pic-small\"src=\"" + data[i].picUrl + "\" />";
    }
    anew += "\
      <p>\
        "+ data[i].summary +"\
      </p>\
    </div>\
  </div>\
";

这样的代码看起来杂乱不堪,甚至还加入了判断条件,想要修改起来相当麻烦。好在,Javascript 模板引擎能够较好的解决这样的问题,而 Handlebars 属于这一类中较好的工具了。

引入 Handlebars

Handlebars 使用 json 作为数据结构,使用类似于 JAVA 中 EL 表达式的形式,把结构化数据导入 html 标签中,进而插入到页面。

如果使用 Handlebars 来完成这一工作,那么操作如下:

假设 JSON 数据结构如下:

var data = [
    {
        "clickNum": 0,
        "commentNum": 0,
        "id": 147,
        "picUrl": null,
        "publicName": "新闻",
        "summary": "5 月 17 日下午,...",
        "time": "2015-05-29 18:08",
        "title": "新闻标题"
    },
    {
        "clickNum": 0,
        "commentNum": 0,
        "id": 147,
        "picUrl": null,
        "publicName": "新闻",
        "summary": "5 月 17 日下午,...",
        "time": "2015-05-29 18:08",
        "title": "新闻标题"
    }
];

把 JSON 格式的数据赋值给变量 data,当然也能直接把 AJAX 传来的 JSON 数据赋值给 data。

接着是写 handlebars 模板,text/x-handlebars-template 是 Handle 模板的预设类型,每个模板要专门放入一个 script 标签中,并加入 id 属性,方便获取。

<script id="template-data" type="text/x-handlebars-template">
{{#each this}}
<div class="row card anews">
    <div>
        <div class="pic-head"></div>
        <h2 class="anews-title">
            <a href="{{id}}.html">{{title}}</a>
        </h2>
    </div>
    <div class="anews-info">
        <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
        <a href="#">{{publicName}}</a>&nbsp;&nbsp;&nbsp;&nbsp;
        <span class="glyphicon glyphicon-time" aria-hidden="true"></span>
        {{time}}&nbsp;&nbsp;&nbsp;&nbsp;
        <span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span>
        ( {{clickNum}} )&nbsp;&nbsp;&nbsp;&nbsp;
        <span class="glyphicon glyphicon-edit" aria-hidden="true"></span>
        ( {{commentNum}} )&nbsp;&nbsp;&nbsp;&nbsp;
    </div>
    <div class="anews-summary">
      {{#if picUrl}}
      <img class="pic-small" src="{{picUrl}}" />
      {{/if}}
        <p>
        {{summary}}
        </p>
    </div>
</div>
{{/each}}
</script>

相比直接的 JS 字符串,Handlebars 模板显得相当简洁,不杂乱。{{#XXX XXX}} 格式的标签为 Handlebars 的 Helper,其中的 #each,#if 都是内置的 Helper。{{#each this}} 表示在当前上下文(当前 JSON 根属性为数组)进行遍历,可以实现模板内容的循环,用以代替 jQuery 的 foreach 或 javascript 的 for in。{{变量名}} 表示直接输出当前上下文中制定变量的值。{{#if 变量名}} 对变量值进行判断,只有当变量值不为 Null、undefined、"",[],false 等表示空或假的值时,才会进入 {{#if }} {{/if}} 中的判断体。这里表示只有当 picUrl 值存在时才会打印出其中的 img 标签。

既然数据和模板都完成了,那么接下来就是对数据和模板的整合

<script src="js/jquery-1.11.3.min.js"></script>
<script src="js/handlebars-v3.0.3.js"></script>
<script>

// 编译模板
var template = Handlebars.compile($("#template-data").html());

// 整合数据
var html = template(data);

// 页面加入 html
$("#area").append(html);
</script>

这样就完美地实现了 html 中数据和代码的分离

高级用法

Handlebars 的 Helper 标签是相当强大的,可以完全自定义。如果我只想从中取出 id 在一定范围内的数据,利用自定义标签,加入绑定 Helper 操作

Handlebars.registerHelper("range", function(val, from, to, options) {
        if(val>= from && val <= to) {
            return options.fn(this)
        }
});

修改模板如下:

<script id="template-data" type="text/x-handlebars-template">
{{#each this}}
{{#range id 100 200}}
<div class="row card anews">
    <div>
        <div class="pic-head"></div>
        <h2 class="anews-title">
            <a href="{{id}}.html">{{title}}</a>
        </h2>
    </div>
    <div class="anews-info">
        <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
        <a href="#">{{publicName}}</a>&nbsp;&nbsp;&nbsp;&nbsp;
        <span class="glyphicon glyphicon-time" aria-hidden="true"></span>
        {{time}}&nbsp;&nbsp;&nbsp;&nbsp;
        <span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span>
        ( {{clickNum}} )&nbsp;&nbsp;&nbsp;&nbsp;
        <span class="glyphicon glyphicon-edit" aria-hidden="true"></span>
        ( {{commentNum}} )&nbsp;&nbsp;&nbsp;&nbsp;
    </div>
    <div class="anews-summary">
      {{#if picUrl}}
      <img class="pic-small" src="{{picUrl}}" />
      {{/if}}
        <p>
        {{summary}}
        </p>
    </div>
</div>
{{/each}}
</script>

这样只有满足条件的数据才会和模板进行整合,否则不输出为 html。

自定义 Helper 是 Handlebars 相当强大的功能,这里我就不详细讲解了。

具体可参考:

评论区

发表评论
用户名
(必填)
电子邮箱
(必填)
个人网站
(选填)
评论内容
Copyright © 2017 dremy.cn
皖ICP备16015002号