追加 var result = $("#result"); $("").text(data.title).appendTo(result); $("").text(data.description).appendTo(result); var ul = $("").attr("class", "cf").appendTo(result); for (var i = 0; i < data.list.length; i++) { $("") .append("No." + (i + 1) + "") .append("name: " + escape(data.list.name) + "") .append("score: " + escape(data.list.score) + "") .appendTo(ul); } パターン2 1ループごとに文字列連結でHTMLを作る -> 追加 var result = $("#result"); result.append('' + escape(data.title) + '<" /> 追加 var result = $("#result"); $("").text(data.title).appendTo(result); $("").text(data.description).appendTo(result); var ul = $("").attr("class", "cf").appendTo(result); for (var i = 0; i < data.list.length; i++) { $("") .append("No." + (i + 1) + "") .append("name: " + escape(data.list.name) + "") .append("score: " + escape(data.list.score) + "") .appendTo(ul); } パターン2 1ループごとに文字列連結でHTMLを作る -> 追加 var result = $("#result"); result.append('' + escape(data.title) + '<" />

JavaScriptでとあるデータから動的にHTMLを生成したい時

JavaScriptって柔軟ですよね。

サーバも書けるし、フロントエンドであればHTMLをいじったりCSSを変えたりと、いろんなことが出来ます。
さらには、jQueryを使えばもっと直感的に使えますし。

今回はよくある(?)パターンとして、非同期で通信して戻ってきたデータからHTMLを生成してページを書き換える、って時のお話。
こういう時ってどうしてますか?(通信成功時の場合)

いくつかやり方がありそうなので、いろいろ列挙してみようと思います。

使うデータは・・・

var data = {
  title: "テストの点数",
  description: "この前の資格試験のテスト",

  // 100人分
  list: [
    { name: 'name-1', score: 10 },
    { name: 'name-2', score: 20 },
    { name: 'name-3', score: 30 },
  ]
};

のような感じ。

jQueryを使うのと、エスケープ処理された文字列を返してくれるescapeという関数を書いておくとします。(cfはclearfix, #resultは結果表示領域)

パターン1

1ループごとにjQueryオブジェクトを作る -> 追加

var result = $("#result");

$("<h2>").text(data.title).appendTo(result); 
$("<p>").text(data.description).appendTo(result); 

var ul = $("<ul>").attr("class", "cf").appendTo(result); 

for (var i = 0; i < data.list.length; i++) { 
  $("<li>") 
    .append("No." + (i + 1) + "<br />") 
    .append("name: " + escape(data.list[i].name) + "<br />") 
    .append("score: " + escape(data.list[i].score) + "<br />") 
    .appendTo(ul); 
}

パターン2

1ループごとに文字列連結でHTMLを作る ->  追加

var result = $("#result");

result.append('<h2>' + escape(data.title) + '</h2>');
result.append('<p>' + escape(data.description) + '');

var ul = $("<ul>").attr("class", "cf").appendTo(result);

for (var i = 0; i < data.list.length; i++) {
  ul.append(
    "<li>" +
    "No." + (i + 1) + "<br />" +
    "name: " + escape(data.list[i].name) + "<br />" +
    "score: " + escape(data.list[i].score) + "<br />" +
    "</li>"
  );
}

パターン3

全てのHTML文字列を文字連結により生成 ->  追加

var result = $("#result");

var html = '<h2>' + escape(data.title) + '</h2>' +
  '<p>' + escape(data.description) + '' +
  '<ul class="cf">';

for (var i = 0; i < data.list.length; i++) {
  html +=
    "<li>" +
    "No." + (i + 1) + "<br />" +
    "name: " + escape(data.list[i].name) + "<br />" +
    "score: " + escape(data.list[i].score) + "<br />" +
    "</li>";
}

html += '</ul>';

result.append(html);

パターン4

全てのHTML文字列を配列に追加して連結 -> 追加

var result = $("#result");

var html = [
  '<h2>',
    escape(data.title),
  '</h2>',
  '<p>',
    escape(data.description),
  '',
  '<ul class="cf">'
];

for (var i = 0; i < data.list.length; i++) {
  html.push("<li>");
  html.push("No.");
  html.push(i + 1);
  html.push("<br />");
  html.push("name: ");
  html.push(escape(data.list[i].name));
  html.push("<br />");
  html.push("score: ");
  html.push(escape(data.list[i].score));
  html.push("<br />");
  html.push("</li>");
}

html.push("</ul>");

result.append(html.join(""));

ここからはUnderscore.jsというライブラリを読み込むことで可能になるパターンです。

パターン5

テンプレートを文字列で定義し、template関数でHTMLを生成 -> 追加

var template = [
  "<h2><%- title %></h2>",
  "<p><%- description %>",
  '<ul class="cf">',
  "<% _.each(list, function(val, i) { %>",
    "<li>",
      "No.<%- i + 1 %><br />",
      "name:  <%- val.name %><br />",
      "score: <%- val.score %><br />",
    "</li>",
  "<% }) %>",
  "</ul>"
].join("");

$("#result").append(_.template(template, data));

パターン6

テンプレートを外部に定義し、template関数でHTMLを生成 -> 追加

外部テンプレート

<script id="template" type="text/template">
<h2><%- title %></h2>
<%- description %>
<ul class="cf">
<% _.each(list, function(val, i) { %>
  <li>
    No.<%- i + 1 %><br />
    name:  <%- val.name %><br />
    score: <%- val.score %><br />
  </li>
<% }) %>
</ul>
</script>

スクリプト

$("#result").append(_.template($("#template").text(), data));

ベンチマーク取ってみました

console.timeとconsole.timeEndでベンチマーク取ってみました。
(それぞれ100件分のデータをHTMLにし、追加処理をするのにかかった合計時間)

パターン1

73.491ms

パターン2

40.411ms

パターン3

18.787ms

パターン4

19.192ms

パターン5

3.152ms

パターン6

3.296ms

結局どれが良いか

パフォーマンス面ではパターン5, 6のようなUnderscoreのテンプレートを使ったものが良い感じです。

<%- %>で出力すればエスケープもしてくれます。

<% %>ならば普通にJavaScriptが動きます。

可読性は・・・人それぞれ好みや慣れがあると思うので一概に言えないんですが、個人的には

パターン5, 6のような感じで、決められた形として定義しておくほうが見やすいし直しやすいように感じます。

他にももっと効率よくて速くて見やすくて書きやすいようなやり方があったならば知りたいですね。

以上、JavaScriptネタでした。

関連リンク

jQuery

Underscore

Recent Posts

Archive