Help us understand the problem. What is going on with this article?

テンプレートエンジンEJSで使える便利な構文まとめ

More than 3 years have passed since last update.

※gulp-ejsでのビルドを想定しています。

EJSでできること

  • 数や文字列や配列やオブジェクトの宣言と処理(JavaScriptと同じ)
  • HTMLへの値の展開
  • ループと条件分岐
  • 外部ファイルの読み込みとパラメータの引き渡し

<% %>の種類

<% %>

このタグの内側はJavaScriptワールドになる。HTMLとしては出力されない

<% var myParam = 'Hello! EJS!'; %>

<%= %>

中にあるJS変数の値をエスケープ込みで展開する。<>がエスケープされて出力されるので、HTMLタグ等は<%- %>を使う

demo.ejs
<div><%= myParam %></div>
demo.html
Hello! EJS!

使用例

サイトのメタ情報をオブジェクトに定義し、タグ内に展開する

demo.ejs
<% var meta = { title:'site name', desc:'このサイトの説明' }; %>

<title><%= meta.title %></title>
<meta name="description" content="<%= meta.desc %>" />

<%- %>

中にあるJSの値をエスケープなしで展開する

demo.ejs
<% var para = '<p>Hello EJS!</p>'; %>
<div><%= para %></div>
<div><%- para %></div>
demo.html
<div>&lt;p&gt;Hello EJS!&lt;/p&gt;</div>
<div><p>Hello EJS!</p></div>

<%# %>

内側がコメントとなり、HTMLの出力結果に影響しない。

demo.ejs
<%# EJS Comment! %>
<!-- HTML Comment! -->
demo.html
<!-- HTML Comment! -->

<%% %>

通常は使わないが、Yeoman等でEJS自体をEJSでテンプレート化したい時に<% %>のエスケープとして使用する。

template.ejs
<%% var hoge = 'hogehoge'; %>
<%%- include('./head'); %>
<h1><%= templateProp %></h1>

templatePropに変数を展開してoutput.ejsとして出力した想定

output.ejs
<% var hoge = 'hogehoge'; %>
<%- include('./head'); %>
<h1>Title Text</h1>

include()関数

<%- include('./_partial', {param:'param'}) %>

第一引数に読み込むEJSファイルへの相対パス(自ファイルが基準)、
第二引数にそのEJSに渡すパラメータを指定できる。
パスは拡張子の「.ejs」を省略できる。

似たものにincludeディレクティブがある。

<% include _partial %>

include()関数と違い、

  • パラメータを投げられない
  • パスを変数から作れない

というデメリットがあるので、include()関数を使う方が便利。

変数のスコープと受け渡し

1つのEJSファイルの中でスコープが閉じている。include()したファイルへ変数を渡すには次の2つの方法がある。

  • include()の第2引数で渡す
  • グローバル変数としてvarを付けずに変数宣言する

例:ファイル間でローカル変数の共有は不可

one.ejs
<% var hoge = 'hoge'; %>
<% foo = 'foo'; %>
two.ejs
<%# エラー %>
<%= hoge %>

<%# エラーにならない %>
<%= foo %>

例:include()の第2引数の使い方

オブジェクトのキー名が、子ファイルのローカル変数名と対応する。

one.ejs
<% var myData = {head:'Head text', body:'Body text'}; %>
<% include('two.ejs', {var1:'hoge', data:myData}); %>
two.ejs
<section class="<%= var1 %>">
  <h2><%= data.head %></h2>
  <p><%= data.body %></p>
</section>

子に投げていないキー名をいきなり参照しようとするとエラーになってしまう。
キー名があるかどうか分からない場合は、変数がundefinedの時は初期値をセットするようにするとエラーにならない。

two.ejs
if (typeof var1 === 'undefined') { var var1 = ''; }
if (typeof data === 'undefined') { var data = {head:'default', body:'default'}; }

<section class="<%= var1 %>">
  <h2><%= data.head %></h2>
  <p><%= data.body %></p>
</section>

ループ

for

<% for (var i = 0; i < 10; i++) { %>
<p>このループは<%= i+1 %>回目です。</p>
<% } %>

古典的なループその1。

while

<% var counter = 1; %>
<% while (counter <= 10) { %>
<p>このループは<%= counter %>回目です。</p>
<% counter++; %>
<% } %>

古典的なループその2。

array.forEach()

<% var ary = ['アイテム1', 'アイテム2', 'アイテム3']; %>
<% ary.forEach(function (value, key) { %>
<p><%= key %>: <%= value %></p>
<% }); %>

配列の中身を順番に取り出すならこれが一番使いやすい。

for...in, for...of

<% var ary = ['アイテム1', 'アイテム2', 'アイテム3']; %>

<% for (var key in ary) { %>
<p><%= ary[key] %></p>
<% } %>

<% for (var item of ary) { %>
<p><%= item %></p>
<% } %>

for...inやES6のfor...ofも使用できる。for..inは順番が不確定なので、テンプレートエンジンでは使わない方が良いかも。

条件分岐

if

<% if (data.type === 'type1') { %>
<p class="type1">This template is for type1.</p>

<% } else if (data.type === 'type2') { %>
<p class="type2">This template is for type2.</p>

<% } else { %}
<!-- else -->
<% } %>

JavaScriptのif/elseを使うことができる。

switch

2015年11月現在、<% %>で分断したswitch文は実装されていないので注意。

例:これは動く

<% var text = ''; %>
<% var state = 0; %>
<% switch ( state ) {
  case 0:
    text = 'case0';
    break;
  case 1:
    text = 'case1';
    break;
} %>
<p><%= text %></p>

例:これは動きそうだけど動かない

<% var text = ''; %>
<% var state = 0; %>
<% switch ( state ) { %>
<% case 0: %>
  <p>case0</p>
<% break; %>
<% case 1: %>
  <p>case1</p>
<% break; %>
<% } %>

関数

ひとまとまりのHTMLテンプレートを関数化して再利用できる。ループや条件分岐を多用するとどんどんネストが深くなってしまうので、ときどき関数にくくり出すと整理しやすい。

demo.ejs
<%# generateItem関数を定義 %>
<% var generateItem = function(name, dataList){ %>
  <ul class="<%= name %>">
    <% dataList.forEach(function (dataItem, index) { %>
      <li class="<%= name + '__' + index %>"><%= dataItem %></li>
    <% }); %>
  </ul>
<% }; %>

<%# ここで定義した関数を実行 %>
<%- generateItem('item-list', ['ホーム', '新着情報', '会社概要']); %>

自分がWeb制作でよくやるEJSの運用

JekyllやHugoで言うfront-matterっぽいものが欲しいので、以下のような機能をテンプレート化してコーディングしている。

  • グローバルで参照できるオブジェクトを全ファイルで使えるように、毎回先頭で_data.ejsをinclude()
  • 他のファイルからinclude()をコピペしてもそのまま動くように、ルートまでのパスを変数化して全ファイルで読み込むようにしている
  • あとで必要なことに気付くと面倒臭いので、例えすぐには使わなくともinclude()先には常に同じ名前でグローバルのdataオブジェクトを渡すようにする
data/_data.ejs
<% getData = function () {
    return {
      meta: { ... },
      navItems: [...]
    }
};
index.ejs
<% var ejsRoot = './'; %>
<% include(ejsRoot + 'data/_data'); var data = getData(); %>
<% data.root = './'; %>
<%# parts/_header %> <%- include(ejsRoot + 'parts/_header', {data:data}); %>
<%# ここに何か書く %>
<%# parts/_footer %> <%- include(ejsRoot + 'parts/_footer', {data:data}); %>

EJSを使ったHTMLコンポーネントの設計手法

拙作のスライドで詳しく紹介している。

コンポーネント単位で考えるWeb制作
http://media-massage.net/works/docs/componentweb/

slide9.png

EJS参考ページ

http://www.embeddedjs.com/
https://www.npmjs.com/package/ejs

y_hokkey
1988年生まれ。多摩美グラフィックデザイン学科を中退。デザイナーとしてグラフィック・エディトリアル・Web・UIのデザインを経験した後、Webフロントエンドエンジニアも経験。現在はITコンサルタントとして外資系SIerに在籍中。元LIG社員。※投稿内容は私個人の意見であり、所属企業・部門見解を代表するものではありません。
http://media-massage.net/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした