(この記事はGrimoireJSアドベントカレンダー2016の9日目です。)
前回はGrimoireJSの基本的な構造についてという記事でGomlNodeとComponentについて簡単に紹介しました。
ページにgomlを埋め込むことでそれがツリーとしてパースされ、そのままのシーンがレンダリングされます。
でも、せっかくhtmlページに埋め込むなら、ほかのhtml要素と同じように動的に操作したくなりませんか?
ということで今回は、gomlから構築されたGomlNodeツリーをスクリプトからどのように操作するのかを紹介していきたいとおもいます。
3種のインタフェース
GrimoireJSは、gomlから作られたシーン中のGomlNodeを簡単に操作するためのインタフェースを提供しています。
このインタフェースは
- GrimoireInterface
- GomlInterface
- NodeInterface
の3段階に分かれていて、それぞれ操作する対象が違います。
Interface | 対象 | コード |
---|---|---|
GrimoireInterface | 環境全体 | gr |
GomlInterface | htmlに埋め込まれた各goml | gr("selector") |
NodeInterface | GomlNodeツリー中の各ノード | gr("selector")("") |
まずは、公式のチュートリアルから引っ張ってきた以下のコードを見てみましょう。
gr(function() {
setTimeout(function(){
gr("#main")("#green-mesh").setAttribute("position", "3,0,0");
},1000);
});
GrimoireInterface
gr
は、GrimoireJSを読み込むとグローバルに定義されるGrimoireInterfaceです。
よく見ると1行目と3行目で違う使い方をされていますが、まずは3行目の方を見てみましょう。
各インタフェースに共通しているのは、関数としてセレクタを渡して対象を検索できることです。
それを踏まえて先程のサンプルコードを思い出してみると、
gr("#main")("#green-mesh").setAttribute("position", "3,0,0");
gr
に"#main"
というセレクタが渡され、idが"main"であるスクリプトタグに対応するgomlを検索して、GomlInterfaceが返されます。
そのGomlInterfaceに対して"#green-mesh"
を渡すことで、このgoml中のidが"green-mesh"であるノードが検索され、NodeInterfaceが返されてます。
また、NodeInterfaceに対しての操作は、対象となるすべてのノードに対して実行されるので、setAttribute()
すると複数ノードに同時に属性を設定できます。
ここではid指定なので対象ノードは一つだけですが、例えば、gr("#main")("mesh")
とすればすべてのmesh
タグを一度に操作することができます。
基本的にこれらの機能を使うことが多いですが、それぞれのインタフェースには他にもいくつか機能があるので、その辺りも紹介します。
GrimoireInterface
まず先程のサンプルの1行目で使われていた機能。
functionを渡して関数として呼び出す
functionを渡すと、Gomツリーがロードされた直後に渡した関数がコールバックされます。
Gomツリー上の要素をいじるときは当然ツリーのロードが完了していないといけないので、基本的にこの中で操作を行うことになります。
gr.registerComponent()
gr.registerComponent("ComponentName", {
attribute:{},
$awake:function(){}
})
>新しいコンポーネントを作るときに使います。コンポーネント名は`CamelCase`推奨です。
### `gr.registerNode()`
>```js:
gr.registerNode("node-name",["ComponentName"],{attr:"default Value"});
こちらは新しいノードの定義です。ノード名は、
snake-case
推奨です。
上のregisterComponentにも言えることですが、registerはロード完了前にやる必要があるので、gr(function(){})
の中で呼んではダメです。
GomlInterface
実はこいつにはほとんど機能がないのですが、強いて挙げるなら。
gr("selector").getNodeById("id")
gr("selector")("#id")
とするのとほぼ等価ですが、こちらのほうが高速です。
パフォーマンスが必要な場合に使ってください。
ちなみに返り値はNodeInterface
ではなく、GomlNodeの配列です。
NodeInterface
一番多機能です。よく使う順で紹介。
setAttribute
gr("slctr")("slctr").setAttribute("attrName","value")
そのまんま属性の設定です。よく使います。
getAttribute
gr("slctr")("slctr").getAttribute("attrName")
属性の取得です。
これもよく使いますが、対象ノードが存在しないと例外を投げます。
また、対象が複数存在するとき、最初のノードの属性を返します。
forEach
gr("slctr")("slctr").forEach(function(node,gomlIndex,nodeIndex){
// for all node.
console.log(node);
})
対象ノードに反復処理ができます。ノード本体は第一引数で、そのノードの属するgomlのインデックスとnodeのインデックスも渡されます。
汎用性高いのでよく使います。
addComponent
gr("slctr")("slctr").addComponent("ComponentName",{attr:"value"})
コンポーネントをノードに追加します。
動的にコンポーネントを制御するのに使います。
delete
gr("slctr")("slctr").delete()
ノードを削除します。
count
var count = gr("slctr")("slctr").count()
対象ノードの個数です。
first
var node = gr("slctr")("slctr").first()
最初のノードを返します。一つも存在しないとnullを返します。
single
var node = gr("slctr")("slctr").single()
firstとほぼ同じですが、対象が存在しなかったり、複数存在するときには例外を投げます。
対象がひとつしかないことを期待するならこっちを使ったほうが安全です。
まとめ
大抵、gr()()
で取得するノードインタフェースを通して操作する。