
jsonを使用したテンプレートエンジン「jquery.jsontpl.js」です。jQueryバージョン1.5以上で動作します。
特徴は、テンプレートのパースに正規表現置換やevalなどせず、jQueryの高レベルAPIのみを使用している点です。テンプレート内ではほぼ普通にjavascriptが使えますので、つまりテンプレート内で条件分岐、反復制御ができます。テンプレートは入れ子にもできます。よくある特殊制御構文とか特にありませんので、学習コストが低いかも知れません。
アルファバージョンです。数日でテキトーに作ったので、コンセプトすら正しいのか不明です。
[2011.01.29更新]
デモサイトを作りました[デモ]。あと、IE6でも動作するよう修正しました。正規表現つかっちまった。
テンプレートは下記のように使用します。
$.jsontpl.parse('./tpl.html','./data.json').appendTo(selector);
テンプレート内に下記のようなタグを記述すると変数名nameと解釈され、値に置換されます。
<var name="name"></var>
jsonデータは連想配列の配列として渡します。連想配列のキーがテンプレート変数名です。
[{"name":value}, {"name":value2}, {"name":value3}]
jQuery.jsontpl.getContextメソッドにてコンテキストオブジェクトcontextを取得することができます。コンテキストというのは要するに現在のテンプレートの範囲ということです。contextオブジェクトから、現在のコンテキストでの変数を取得したり、DOM操作をしたりできます。
var context = $.jsontpl.getContext();
var name = context.getvar("name");
テンプレート内のdomにはid属性を指定してスクリプトでパース時に制御することができます。テンプレート内のid属性は、衝突を避けるためパース後に削除されます。テンプレート、つまり複製されるものなので、適用後にidが必要になるはずはないという訳です。別にclassでも構いませんが。
context.find("#flag")
変数スコープには注意が必要です。グローバル空間で衝突しないように下記のように記述するとよいです。
<script type="text/javascript">
(function() {
var context = $.jsontpl.getContext();
})();
</script>
jsontplプラグインはjQuery.jsontpl名前空間を占有します。jQuery.jsontplはjQuery.subclassそのものなので、jQuery(selector)とjQuery.jsontpl(selector)はよく似ています。ただし、下記のメソッドを追加、またはオーバーライドしています。詳しくはソースを参照してください。
jQuery.jsontpl.ajax
jQuery.jsontpl.getTpl
jQuery.jsontpl.getJSON
jQuery.jsontpl.get
jQuery.jsontpl.getContext
jQuery.jsontpl.parse
jQuery.jsontpl.fn.getvar
jQuery.jsontpl.fn.parse
jQuery.jsontpl.fn.appendTo
jQuery.jsontpl.fn.prependTo
jQuery.jsontpl.fn.insertBefore
jQuery.jsontpl.fn.insertAfter
使用例
data.json
[
{
"name": "Yamada",
"mail": "yamada@example.com",
"blood": "A"
},
{
"name": "Yamamoto",
"mail": "yamamoto@example.com",
"blood": "A"
},
{
"name": "Suzuki",
"mail": "suzuki@example.com",
"blood": "B",
"detail":{
"data1":"hoge",
"data2":"hoge",
"data3":"hoge"
}
}
]
index.html
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<title>jQuery Template</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<style type="text/css">
table,th,td {
border:1px solid #ccc;
}
th {
background-color: #e0e0f0;
}
</style>
<script src="./common/js/jquery.1.5.js" type="text/javascript"></script>
<script src="./common/js/jquery.jsontpl.js" type="text/javascript"></script>
<script type="text/javascript">
//<![CDATA[
$(document).ready(function(){
// テンプレートとJSONをサーバーから取得
$.jsontpl.parse('./tpl.html','./data.json').appendTo('.movie');
});
//]]>
</script>
</head>
<body>
<table class="movie">
<tr>
<th>名前</th>
<th>メール</td>
<th>血液型</td>
<th>A型</th>
<th>詳細情報</th>
</tr>
</table>
</body>
</html>
tpl.html
<tr>
<td><var name="name"></var></td>
<td><var name="mail"></var></td>
<td><var name="blood"></var></td>
<td id="flag"></td>
<td id="subtable" class="subtable">
</td>
</tr>
<script type="text/javascript">
//<![CDATA[
(function() {
// コンテキストオブジェクトを取得
var context = $.jsontpl.getContext();
// テンプレート内で条件分岐例
if (context.getvar("blood") == 'A') {
context.find("#flag").html("true");
}
// サブテンプレートを挿入
$.jsontpl.parse('./tpl2.html', context.getvar("detail")).appendTo('#subtable');
})();
//]]>
</script>
tpl2.html
<div class="hoge">
data1:<var name="data1"></var>
<br />data2:<var name="data2"></var>
<br />data3:<var name="data3"></var>
</div>
jquery.jsontpl.js(最新版はgithubにて)
(function ($) {
$.jsontpl = $.subclass();
var console = {
log : (window.console) ? window.console.log : function () {}
};
$.jsontpl.params = {
classPrefix : 'jsontpl',
__trailing__: null
};
$.jsontpl.setParams = function (params) {
$.extend($.jsontpl.params, params);
return this;
};
var cache = {};
$.jsontpl.ajax = function (params) {
if (cache[params.url]) {
params.success(cache[params.url]);
return {};
}
params.success = (function() {
var url = params.url;
var orgSuccess = params.success;
return function(a) {
cache[url] = a;
orgSuccess(a);
}
})();
return $.ajax(params);
};
$.jsontpl.getTpl = function (url) {
var ret;
$.jsontpl.ajax({
type: "GET",
url: url,
cache: true,
async: false,
error: function (error) {
console.log(error.statusText + " at " + url);
},
success: function (tpl) {
ret = $.jsontpl(tpl);
}
});
return ret;
};
$.jsontpl.getJSON = function (url) {
var ret;
$.jsontpl.ajax({
type: "GET",
url: url,
cache: true,
async: false,
dataType: 'json',
error: function (error) {
console.log(error.statusText + " at " + url);
},
success: function (json) {
ret = json;
}
});
return ret;
};
$.jsontpl.get = function (tpl, json) {
return {
tpl : $.jsontpl.getTpl(tpl),
json : $.jsontpl.getJSON(json)
};
};
var context;
var getContext = $.jsontpl.getContext = function () {
return context || $('body');
}
$.jsontpl.fn.getvar = function (name) {
return this.data('jsontpl')['var'][name];
}
var _parse = function (tpl, json) {
if (typeof tpl === 'string') {
tpl = $.jsontpl.getTpl(tpl);
}
if (typeof json === 'string') {
json = $.jsontpl.getJSON(json);
} else if ((json && json.constructor !== Array)) {
json = [json];
}
var ret = $.jsontpl('<div />');
for (var idx in json) {
var data = json[idx];
var tpl_tmp = $.jsontpl("<div />");
tpl_tmp.data("jsontpl", {'var':data});
var current_context = context;
context = tpl_tmp;
tpl_tmp.html(tpl.clone());
for (var tplvar in data) {
tpl_tmp.find("[name=" + tplvar + "]").replaceWith(data[tplvar]);
}
ret.append(tpl_tmp.children());
context = current_context;
}
ret.find("[id]").removeAttr("id");
return ret.children();
};
$.jsontpl.parse = _parse;
$.jsontpl.fn.parse = function (json) {
return _parse(this, json);
};
$.jsontpl.fn.appendTo = function (selector) {
getContext().find(selector).append(this);
return this;
};
$.jsontpl.fn.prependTo = function (selector) {
getContext().find(selector).prepend(this);
return this;
};
$.jsontpl.fn.insertBefore = function (selector) {
getContext().find(selector).before(this);
return this;
};
$.jsontpl.fn.insertAfter = function (selector) {
getContext().find(selector).after(this);
return this;
};
})(jQuery);