🐋成员文章

Handlebars学习记录

2017-08-24  本文已影响101人  烈风裘

学习缘由

Handlebars模板引擎从去年就关注了,因为使用类HTML格式/类Vue/类Angular的语法我比较习惯,所以就定在了学习计划中。目前公司后台渲染项目都是使用Handlebars模板引擎,所以这篇博文简单做下学习记录。

模板引擎是做什么的

模板引擎所做的工作简单的说就是:

输入模板字符串 + 数据 => 得到渲染过的字符串

需要重申的是,得到的是经过数据填充的静态字符串。此外,根据页面的结构再拼接其余部分HTML片段,最后在发送到客户端。因此,在需要SEO场景条件下比较合适,比如:社交、新闻、博客、站点导航等网站是必须使用的。

此外,模板引擎除了Handlebarsjs还有:Jade templatingUnderscore TemplatesMustache等。除非现有的各类模板引擎不适合自己的业务,建议在选择开源项目的时候还是选择口碑好一些、目前还在维护的项目。

Basic Usage

一、JS模板编译

可以将模板字符串写在*.hbs中,也可以是在<script>中定义

二、插值

语法和Angular、Vue很像:{{value}}{{{Html}}}

这里需要注意在传入的变量中不能有特殊字符:

! " # % & ' ( ) * + , . / ; < = > @ [ \ ] ^ ` { | } ~

如果有的话需要用[]包起来(也可以是'或者"):

{{#each articles.[10].[#comments]}}
  <h1>{{subject}}</h1>
  <div>
    {{body}}
  </div>
{{/each}}

三、Helpers

Helper使用前需要注册,一般用于对数据的再加工,比如:

1. 单行 Helper

单行的Helper可以是双大括号{{xx}},或者是{{{xx}}}包裹,区别在于:

{{{name data1 data2 hashKey1=hashValue1 hashKey2=hashValue2}}}
参数(格式固定)

参数含义有位置和书写格式确定,使用空格分离,分为三类:

注册Helper
Handlebars.registerHelper('name', function(data1, data2, options) {
    // options.name: 当前helper的名称, 例如: debug
    // options.hash[hashKey1] === hashValue1
    // options.hash[hashKey2] === hashValue2
    // options.fn(this): 块级helper内部的模板函数
    // options.inverse: else分支的模板函数
    // options.data.root: 当前页面填充的数据对象
    // return 的字符串就是渲染的Markup片段
});
示例
{{{link "See more..." href=story.url class="story"}}}

Handlebars.registerHelper('link', function(text, options) {
  var attrs = [];

  for (var prop in options.hash) {
    attrs.push(
        Handlebars.escapeExpression(prop) + '="'
        + Handlebars.escapeExpression(options.hash[prop]) + '"');
  }

  return new Handlebars.SafeString(
    "<a " + attrs.join(" ") + ">" + Handlebars.escapeExpression(text) + "</a>"
  );
});

2. 块级 Helper

带有内部模板结构的写法,参数和注册方法同上,具体写法如下:

{{#name data1 data2 hashKey1=hashValue1 hashKey2=hashValue2}}
  内部模板
{{/name}}
示例
{{#bold}}{{body}}{{/bold}}

Handlebars.registerHelper('bold', function(options) {
  return new Handlebars.SafeString(
      '<div class="mybold">'
      + options.fn(this)
      + '</div>');
});

3. 输出原始 Blocks

书写原始的mustache语句块:

示例
// 模板
{{{{raw-helper}}}}
  {{bar}}
{{{{/raw-helper}}}}

// 对应的Helper函数
Handlebars.registerHelper('raw-helper', function(options) {
  return options.fn();
});

// 结果
{{bar}}

4. 已经注册好的常用Helper:

if/else/unless/with/each/log/blockHelperMissing/helperMissing

5. 嵌入子Helper(Subexpressions)

意思是,在父Helper中传入子Helper的模板String,语法是这样的:

{{outer-helper (inner-helper 'abc') 'def'}}

6. 删除多余换行符(Inline)

正常书写block是有换行符的,Inline模式可以将换行符都删除。注意加~的位置!

示例
// 模板
{{#each nav ~}}
  <a href="{{url}}">
    {{~#if test}}
      {{~title}}
    {{~^~}}
      Empty
    {{~/if~}}
  </a>
{{~/each}}

// 数据
{
  nav: [
    {url: 'foo', test: true, title: 'bar'},
    {url: 'bar'}
  ]
}

// 结果
<a href="foo">bar</a><a href="bar">Empty</a>

7. 输出原始数据

是的,原封不动的输出,有两种方式:

\这里填写你要输出的原始String
{{{{raw}}}}
这里填写你要输出的原始String
{{{{/raw}}}}

8. each Helper的as语法

遍历的同时提取value-key,便于内部使用,下面的例子一目了然。

{{#each array as |value key|}}
  {{#each child as |childValue childKey|}}
    {{key}} - {{childKey}}. {{childValue}}
  {{/each}}
{{/each}}

四、Partials

这个可以理解为子模板,用于模板复用,子模板继承当前的上下文变量环境。使用前需要注册,这个和Helper一致。

Handlebars.registerPartial('myPartial', '{{name}}')

Partials使用场景包括:Footer(友情链接)、Header(Logo登录)、Nav(导航)等。

1. 单行模板

{{> Partial名称 key1=value2}}
动态模板

通过chooseHelper这个Helper帮忙选择使用哪个Partial,chooseHelper应该返回已注册的Partial名称

括号中使用Helper的语法

{{> (chooseHelper) }}

2. 块级模板

块级需要加#标。如果使用Vue,这部分和slot的概念很像。这里分三类:

fallback方案
{{#> myPartial }}
  Failover content(如果myPartial未定义显示这里的东西)
{{/myPartial}}
内部通过@partial-block获取外部block内全部模板
// 模板内容
{{#> layout }}
   <p> layout中的默认全部slot</p>
{{/layout}}

// layout模板内容
{{> @partial-block }}

// 结果
<p> layout中的默认全部slot</p>
将子模板嵌入具体位置(具有名字的slot方案)

这个概念和Vue的具名Slot概念一致,直接贴代码,简单来说:各回各家,各找各妈。

// 模板
{{#> layout}}
  {{#*inline "nav"}}
    My Nav
  {{/inline}}
  {{#*inline "content"}}
    My Content
  {{/inline}}
{{/layout}}

// layout模板内容
<div class="nav">
  {{> nav}}
</div>
<div class="content">
  {{> content}}
</div>

// 结果
<div class="nav">
  My Nav
</div>
<div class="content">
  My Content
</div>

五、注释

{{!-- 这段注释只在源码中显示 --}}
{{! 这段注释只在源码中显示 }}
<!-- 这段注释会在最终的HTML中显示 -->

六、APIs

Handlerbar提供的API分三类:

需要说明的API:

Handlebars.escapeExpression(string)

字符转义函数,将string中的 &, <, >, ", ', `, = 变为转义字符. 保证传入的字符串是安全的。例如:

hbs.Utils.escapeExpression('<script>alert(1)</script>')
// 转化为
<script>alert(1)</script>
// 在html中显示字符串
<script>alert(1)</script>

如果上面具有攻击性的字符串未转义,将在浏览器中弹出alert对话框。

new Handlebars.SafeString(string)

标记内容是安全的,单独使用并不起什么作用:

new hbs.SafeString('<script>alert(1)</script>')
// 返回
SafeString { string: '<script>alert(1)</script>' }

需要和上面的escapeExpression组合使用:

Handlebars.registerHelper('link', function(text, url) {
  text = Handlebars.Utils.escapeExpression(text);
  url  = Handlebars.Utils.escapeExpression(url);

  var result = '<a href="' + url + '">' + text + '</a>';

  return new Handlebars.SafeString(result);
});

模板渲染过程

在Express中默认使用的``hbs```模块渲染Handlerbars模板,渲染过程是这样子的:

知识图谱

Handlerbars结构.png

使用建议

参考

上一篇下一篇

猜你喜欢

热点阅读