🦁

JavaScriptのテンプレートエンジンHandlebars入門

2020/11/06に公開

Handlebarsを知らないという同僚がいたので、まとめてみます。
ただのテンプレートエンジンでデータバインディングとかはないんですが、もし使いどころがあればご参考までに。

基本的には、
http://handlebarsjs.com/
に詳しく書いてあるので、そちらを見てください。

Handlebarsとは

Handlebarsとはいわゆるテンプレートエンジンで、
JavaScriptの値を参照してHTMLを生成できるもの。

書き方

テンプレートは

<div>{{name}}</div>
<div>{{age}}</div>

という書き方をします。
{{XXX}}内のxxxはJavaScriptのプロパティです。
{{XXX}}と書くことにより、JavaScriptの値を参照して、
それをHTMLとして生成します。

<div>{{person.name}}</div>
<div>{{person.age}}</div>

という書き方もできます。そのときは値を

   person : {
      name: "Satoshi",
       age : 33,
    }
  }

みたいに渡してあげることが可能です。

Handlebarsを試す

まずはjqueryとhandlebarsをインストールします。

$ bower install jquery handlebars

ではちょっと試しに書いてみましょう。

test.html
<html>
<head>
<script type="text/javascript" src="./bower_components/jquery/dist/jquery.min.js"></script>
<script type="text/javascript" src="./bower_components/handlebars/handlebars.min.js"></script>
  <script type="text/x-handlebars-template" id="template">
    <h1>{{name}}</h1>
    <div>{{age}}</div>
  </script>
  <script>
    window.onload = function() {
        var source = $("#template").html();
        var template = Handlebars.compile(source);
        var values = {
            name : "Satoshi Watanabe",
            age : 33
        };
        var html = template(values);
        console.log(html);
        $("#contents").html(html);
    }
  </script>
</head>
<body id="contents">
</body>
</html>

これを行うことにより

<h3>Satoshi Watanabe</h3>
<div>33</div>

が表示できます。

build-inのhelper

Handlebarsにはいくつかhelperが用意されているので、それを紹介します。

each

eachはイテレータとして、要素を順番に使用することができます。

<table border="1">
  {{#each momoclo}}
    <tr>
       <td>{{name}}</td>
       <td>{{color}}</td>
     </tr>
   {{/each}}
<table>

とした場合、momocloオブジェクトの要素をひとつひとつ参照します。

    var source = $("#template").html();
    var template = Handlebars.compile(source);
    var values = {
        momoclo : [
            {name : "Kanako Momota", color: "red"},
            {name : "Ayaka Sasaki", color: "pink"},
            {name : "Shiori Tamai", color: "yellow"},
            {name : "Momoka Ariyasu", color: "green"},
            {name : "Reni Takagi", color:"purple"},
        ]
    };
    var html = template(values);
    $("#contents").html(html);

if / unless

{{#if author}}
    <h1>{{firstName}} {{lastName}}</h1>
{{else}}
    <h1>Unknown Author</h1>
{{/if}}

authorがtrueになれば、firstName, lastNameを出力します。
なければ、else以下を実行します。
unlessはifの逆でauthorがfalseになれば、実行します。

{{#unless author}}
    <h1>Unknown Author</h1>
{{else}}
    <h1>{{firstName}} {{lastName}}</h1>
{{/unless}}

with

withはjavascriptのwithと同じです。
テンプレートを

    {{#with momoclo}}
       <div>{{Kanako}}</div>
       <div>{{Ayaka}}</div>
       <div>{{Shiori}}</div>
       <div>{{Momoka}}</div>
       <div>{{Reni}}</div>
    {{/with}}

javascriptを

var values = {
     momoclo : {
        Kanako : "red",
        Ayaka :  "pink",
        Shiori : "yellow",
        Momoka : "green",
        Reni : "purple",
    }
};
var html = template(values);

とかくと、出力は以下のようになります。

<body id="contents">
       <div>red</div>
       <div>pink</div>
       <div>yellow</div>
       <div>green</div>
       <div>purple</div>
</body>

lookup

lookupはあるデータをとりだしてそれを別なデータを取り出すのに使うのに使ったりします。
たとえば、

var values = {
   momoclo : [
        {firstname : "Kanako", lastname : "Momota"},
        {firstname : "Ayaka", lastname : "Sasaki"},
        {firstname : "Shiori", lastname : "Tamai"},
        {firstname : "Momoka", lastname : "Ariyasu"},
        {firstname : "Reni", lastname : "Takagi"},
  ],
  color : {
        "Kanako" : "red",
        "Ayaka" : "pink",
        "Shiori" : "yellow",
        "Momoka" : "green",
        "Reni" : "purple",
    }
};

というデータがあったとして、
momocloのfirstnameからcolorの値が取りたい時、以下のようにします。

    <ul>
      {{#each momoclo}}
        <li>{{lookup ../color firstname}}</li>
      {{/each}}
    </ul>

そうすると、以下のような出力が得られます。

<ul>
    <li>red</li>
    <li>pink</li>
    <li>yellow</li>
    <li>green</li>
    <li>purple</li>
</ul>

その他(時間があったときに追記)

  • log
  • blockHelperMissing
  • helperMissing

自分でhelperを定義する

helperはHandlebars.registerHelper()を使って自分で定義することができます。
例えば、linkを生成する

Handlebars.registerHelper('link', function(text, url) {
   return new Handlebars.SafeString(
      "<a href='" + url + "'>" + text + "</a>"
    );
});

というものを用意してあげると、
データを

    var values = {
        momoclo : [
            {name : "Kanako Momota", url: "http://ameblo.jp/momota-sd/"},
            {name : "Ayaka Sasaki", url: "http://ameblo.jp/sasaki-sd/"},
            {name : "Shiori Tamai", url: "http://ameblo.jp/tamai-sd/"},
            {name : "Momoka Ariyasu", url: "http://ameblo.jp/ariyasu-sd/"},
            {name : "Reni Takagi", url:"http://ameblo.jp/takagi-sd/"},
            ]
    };

としたときは、以下のように書くことができます。

<ul>
    {{#each momoclo}}
        <li>{{link name url}}</li>
    {{/each}}
</ul>

そうすると結果は以下のようになります。

<ul>
     <li><a href="http://ameblo.jp/momota-sd/">Kanako Momota</a></li>
     <li><a href="http://ameblo.jp/sasaki-sd/">Ayaka Sasaki</a></li>
     <li><a href="http://ameblo.jp/tamai-sd/">Shiori Tamai</a></li>
     <li><a href="http://ameblo.jp/ariyasu-sd/">Momoka Ariyasu</a></li>
     <li><a href="http://ameblo.jp/takagi-sd/">Reni Takagi</a></li>
</ul>

プリコンパイル

Handlebarsにはプリコンパイルしておくことが可能です。
ページの読み込むときにコンパイルする必要がないので、こちらをやっておくてページの表示が早くなります。

handlebarsのnpmでインストールしておき、使います。

$ npm install handlebars

テンプレートファイルを用意します。

test-template.hbs
<div>{{person.name}}</div>
<div>{{person.age}}</div>
<div>{{person.sex}}</div>

テンプレートファイルをプリコンパイルします。

$ handlebars test-template.hbs -f test-template.js

それをhtmlに記述します。
使うjavascriptはhandlebars.jsでもhandlebars.runtime.jsでもどちらでも大丈夫です。

test.html
<div id="output">
<script type="text/javascript" src="./bower_components/jquery/dist/jquery.min.js"></script>
<script type="text/javascript" src="./bower_components/handlebars/handlebars.runtime.min.js"></script>
<script type="text/javascript" src="./test-template.js"></script>
<script type="text/javascript">
var html = Handlebars.templates['test-template.hbs']({
   person : {
      name: "Satoshi",
       age : 33,
       sex : 'M'
    }
});
$('#output').html(html);
</script>

これにより、以下が出力されます。

<div id="output">
    <div>Satoshi</div>
    <div>33</div>
    <div>M</div>
</div>

ここはGruntで自動化できそうですね。
grunt-contrib-handlebarsを使いましょう。

API

Handlbars.xxx のようなメソッドはいくつかあるので、
http://handlebarsjs.com/reference.html
を参照してください。

Discussion