読者です 読者をやめる 読者になる 読者になる

M12i.

学術書・マンガ・アニメ・映画の消費活動とプログラミングについて

Liftフレームワークのチュートリアルを読んでなぜかJavaScriptを書く

ScalaでつくられたWebアプリケーション・フレームワークLiftのチュートリアルを読んでいたら、なぜかJavaScriptのテンプレート・エンジンをつくりたくなってしまいました。

jquery-stpl-1.0.js
https://github.com/mizukyf/jquery-stpl/blob/master/jquery-stpl-1.0.js

以前もっと冷静な理由があって同種のものをつくったことがあるのですが、そのときの参照先はPHPで記述されたSmartyでした。これはJSPVelocityと非常に似通った記法をとるテンプレート・エンジンです(どちらが先か、なんて知りません)。

転じてLiftのそれは、もちろんViewの最前面に位置してはいるのですが、ページ内の要素とControllerとのリンクを非常に簡潔に記述するものでもあります。

それはそれとして(実際今回の.jsとは何の関係もありません)、このLiftのテンプレートではHTML要素のclass属性にこうしたメタ情報を記述します。これがおもしろくって、マネっこしたくなったわけです。

テンプレートといっても、いわゆる文字列を読み込んで値を埋め込むものではありません。DOM要素をパースして、値をセットしていきます。

使い方

次のようなDOMツリーがあったとします。

<div class="t:set?id=foo target other">
    <p class="t:set?content=bar"></p>
    <ul class="t:map?array=arr">
    	<li class="t:set?class=fooN">
            <input type="text" size="25" class="t:set?name=fooN&value=barN" />
        </li>
    </ul>
    <p class="t:with?object=obj"><span class="t:set?content=foo"></span></p>
</div>

ここで、次のようなコードを実行します。stplメソッドの引数に与えているのは、テンプレートに割り当てたい変数です。

jQuery("div.target").stpl({
	foo: "fooValue",
	bar: "barValue",
	arr: [
		{fooN: "foo1Value", barN: "bar1Value"},
		{fooN: "foo2Value", barN: "bar2Value"},
		{fooN: "foo3Value", barN: "bar3Value"},
	],
	obj: {
		foo: "fooValue2",
		bar: "barValue2"
	}
});

すると、次のようなDOMに書き換わります。

<div id="fooValue" class="target other">
    <p>barValue</p>
    <ul>
    	
    <li class="foo1Value">
    		<input value="bar1Value" name="foo1Value" size="25" type="text">
    	</li><li class="foo2Value">
    		<input value="bar2Value" name="foo2Value" size="25" type="text">
    	</li><li class="foo3Value">
    		<input value="bar3Value" name="foo3Value" size="25" type="text">
    	</li></ul>
    <p><span>fooValue2</span></p>
</div>

使い方(もっと詳しく)

変数割り付けの指示はDOM要素のclass属性内に記述します。書式は以下の通り。
([...]で囲んだ箇所はオプションです。)

t:action?param1=value1[&param2=value2[& ... ] ]

アクションと引数
action
行わせるアクションを指定します。set(変数を展開しレンダリング)、map(配列の要素ごとに子要素をレンダリング)、 with(オブジェクトのプロパティにアクセスできる名前空間を生成)の3種が用意されています。
param=value
引数名=変数名という記法。setアクションの場合は引数名はおもにDOM要素のプロパティ名です。いまのところ、mapではarrayが、またwithではobjectが唯一の引数です。
setアクション

setアクションの場合、引数名にid、class、name、valueなどDOM要素プロパティ名をとり、変数から値を得て代入します。例えばset?id=varName1&class=varName2などと指定すると、その要素のid属性にはvarName1変数の値がセットされ、class属性にはvarName2変数の値がセットされます。

特殊な引数名にcontentがあり、content=varNameの形式で指定した値は、そのDOM要素の内容となります(テンプレートでは他のDOM要素が子孫要素として存在していても、それらは上書きされます)。

mapアクション

mapアクションの唯一の引数はarrayです。array=arrVarNameの形式で配列を指定することで、その配列の要素であるオブジェクトのプロパティを、mapアクションを指定された要素の子要素に繰り返し適用していきます。例としては前掲のサンプルを参照してください。

withアクション

withアクションの唯一の引数はobjectです。object=objVarNameの形式でオブジェクトを指定することで、このwith指定されたDOM要素とその子孫要素でオブジェクトのプロパティにアクセスし、テンプレートに割り当てられるようになります。

VelocityやSmartyなどと異なり、stpl.jsは“xxx.yyy”とか“xxx[y]”といった記法を許していません。このような場合にはwithを使用します(例えば、with?object=xxxという指定がされた要素より内側では、xxxyyyプロパティにyyyという名前でアクセスできます)。