Fork me on GitHub

关于学习Handlebars的简单记录

Handlebars简介

  • Handlebars 是 JavaScript 一个语义模板库,通过对view和data的分离来快速构建Web模板。它采用”Logic-less template”(无逻辑模版)的思路,在加载时被预编译,而不是到了客户端执行到代码时再去编译,这样可以保证模板加载和运行的速度。

  • 虽然是无逻辑,但还是有一些简单的逻辑比如if、each等。

  • 可以拿Handlebars的语法风格和一般普通js+html混合的风格作对比:

    1
    2
    3
    4
    5
    6
    7
    8
    //js+html
    1 <% if (names.length) { %>
    2 <ul>
    3 <% names.forEach(function(name){ %>
    4 <li><%= name %></li>
    5 <% }) %>
    6 </ul>
    7 <% } %>
    1
    2
    3
    4
    5
    6
    7
    8
      //Handlebars
    1 {{#if names.length}}
    2 <ul>
    3 {{#each names}}
    4 <li>{{this}}</li>
    5 {{/each}}
    6 </ul>
    7 {{/if}}

    看上去一目了然多了。

基本语法

  • 基本语法很简单,主要就是用大括号将data包括起来:
    • {{data}} 两个会将内容做html编码转换。
    • {{{data}}} 三个则不会转码,如果输入一个html标签,是真的会得到一个标签。

块级表达式

  • 这个也很容易懂,可以定义一个数据块,以#开头,以/结尾,如:

    1
    2
    3
    4
    {{#list people}}
    {{firstName}}
    {{lastName}}
    {{/list}}

    内容渲染:

    1
    2
    3
    4
    5
    6
    7
    {
    people: [
    {firstName: "Yehuda", lastName: "Katz"},
    {firstName: "Carl", lastName: "Lerche"},
    {firstName: "Alan", lastName: "Johnson"}
    ]
    }

    输出结果:

    1
    2
    3
    4
    5
    <ul>
    <li>Yehuda Katz</li>
    <li>Carl Lerche</li>
    <li>Alan Johnson</li>
    </ul>

路径

  • Handlebars支持嵌套的属性,使得用模板处理JSON字符串成为可能。如:

    1
    2
    3
    4
    5
    6
    7
    8
    <div class="entry">
    <h1>{{title}}</h1>
    <h2>By {{author.name}}</h2>

    <div class="body">
    {{body}}
    </div>
    </div>
    1
    2
    3
    4
    5
    6
    7
    8
    var context = {
    title: "My First Blog Post!",
    author: {
    id: 47,
    name: "Yehuda Katz"
    },
    body: "My first post. Wheeeee!"
    };
  • 可以用../语法,相当于当前路径的父级,如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    1 var post = {
    2 title: "Blog Post!",
    3 author: [{
    4 id: 47,
    5 name: "Jack"
    6 },{
    7 id: 20,
    8 name: "Mark"
    9 }]
    10 };
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    1 {{#post}}
    2 {{#if author.length}}
    3 <h3>{{title}}</h3>
    4 <ul>
    5 {{#each author}}
    6 <li>{{../title}}s author is {{name}}</li>
    7 {{/each}}
    8 </ul>
    9 {{/if}}
    10 {{/post}}

    li标签里面已经是在 author 字段之内了,所以要使用 ‘../‘ 来转到上层的 title。

Hepler

  • each
    可以使用内置的{{#each}} helper遍历列表块内容,用this来引用遍历的元素 例如:

    1
    2
    3
    4
    5
    <ul>  
    {{#each name}}
    <li>{{this}}</li>
    {{/each}}
    </ul>
    1
    2
    3
    {
    name: ["html","css","javascript"]
    };
  • if else
    {{#if}}就像使用JavaScript一样,可以指定条件渲染DOM。如果if返回的条件是false,undefined, null, “” 或者 [],则不会渲染DOM;如果存在{{#else}}则执行{{#else}}后面的渲染,如:

    1
    var data = {info:['HTML5','CSS3',"WebGL"],"error":"数据取出错误"}
    1
    2
    3
    4
    5
    6
    7
    8
    9
    {{#if list}}
    <ul id="list">
    {{#each list}}
    <li>{{this}}</li>
    {{/each}}
    </ul>
    {{else}}
    <p>{{error}}</p>
    {{/if}}

    {{#if}}判断是否存在list数组,如果存在则遍历list,如果不存在输出错误信息。

  • unless
    即反向的if else语法,当判定值为false时渲染DOM,如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    {{#unless data}}
    <ul id="list">
    {{#each list}}
    <li>{{this}}</li>
    {{/each}}
    </ul>
    {{else}}
    <p>{{error}}</p>
    {{/unless}}
  • with
    这种情况是返回的json数据有多个对象嵌套的问题,很好用的一个方法,也可以直接通过对象点属性的方法找下去。
    {{#with}}一般情况下,Handlebars模板会在编译的阶段的时候进行context传递和赋值。使用with的方法,我们可以将context转移到数据的一个section里面(如果你的数据包含section)。 这个方法在操作复杂的template时候非常有用。

    1
    2
    3
    4
    5
    6
    <div class="entry">  
    <h1>{{title}}</h1>
    {{#with author}}
    <h2>By {{firstName}} {{lastName}}</h2>
    {{/with}}
    </div>
    1
    2
    3
    4
    5
    6
    7
    {
    title: "My first post!",
    author: {
    firstName: "Charles",
    lastName: "Jolley"
    }
    }

关于Fish里的hbs

  • RequireJS导入hbs模板,并使用Backbone的View加载出来。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    define([
    'hbs!modules/order/order-entry/templates/customer-home-tabs/components/AccountInfoTpl.hbs',
    'i18n!modules/order/order-entry/i18n/OrderEntry'
    ], function (AccountInfoTpl, I18N) {
    return portal.BaseView.extend({
    template: AccountInfoTpl,
    serialize: I18N,
    events: {
    },
    initialize: function (initOptions) {
    },
    afterRender: function () {
    },
    })
    });
  • 模板示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
      <div class="col-md-12 col-xl-12">
    <div class="btn-toolbar pull-right">
    <button type="button" class="btn btn-min-width btn-primary js-edit">{{COMMON_MODIFY}}</button>
    <button type="button" class="btn btn-default js-modify-history-pop">{{ORDER_ENTRY_CUSTOMER_MODIFY_HISTORY}}</button>
    </div>
    <div class="btn-toolbar pull-right" style="display:none">
    <button type="button" class="btn btn-min-width btn-primary js-ok">{{COMMON_OK}}</button>
    <button type="button" class="btn btn-min-width btn-default js-cancel">{{COMMON_CANCEL}}</button>
    </div>
    </div>
  • I18N示例

    1
    2
    3
    define({
    ORDER_ENTRY_CUSTOMER_MODIFY_HISTORY: "Modify History"
    });