LoginSignup
16
15

More than 5 years have passed since last update.

HTMLのタグ属性に配列やオブジェクトを指定する

Last updated at Posted at 2015-03-01

素のHTMLでは、もちろんできないんですが、仮想DOM系のライブラリ、

  • React
  • Polymer
  • Riot.js

あたりを使うとできます。設計上ありかという話は置いておいて、便利です。Reactだと何を今更というかJavaScriptなのでやり放題。Polymerもシリアライズが途中に入るもののOKです。

HTML慣れしているほど案外盲点な気がするので、Riotの例を中心に書き留めておきたいと思います。

複数の属性を渡すとき

HTMLで慣れた作法に従うと、例えば、

<path
  file-name={ file.name }
  file-ext={ file.ext }
  file-dir={ file.dir }
  file-icon={ file.icon }>
</path>

みたいにして複数の属性を渡すことを考えると思います。ただ、属性値をひとつずつ分解して渡すのはかなり面倒ですし、JavaScript側で渡すものを増やしたい場合に、HTMLを必ずいじる必要がありその点も面倒です。

  • 面倒1: オブジェクトを分解して渡すのが手間
  • 面倒2: 仕様を変えると必ずHTML変更の必要あり

ここで、もし文字列以外も渡せるとしたら? こう書けます。

<path file={ file }></path>

シンプルですね。あとは、コンポーネント(仮想DOM)内から、オブジェクトにそのままアクセスできるので、好きにすればOKです。(必要があれば、渡された内容のバリデーションは、コンポーネントに任されます)

配列を属性として渡す

複数の子要素を持つコンポーネントはしばしば必要になります。たとえば、こんな構造のコンポーネントがあったとします。

<member-list>
  <programer name="John"></programer>
  <programer name="Sean"></programer>
  <designer name="Becky"></designer>
  <designer name="Taro"></designer>
</member-list>

もし、配列が渡せないとすると、member-listの内側に要素を手動で書いて個別に渡すか、なんらかの情報ソースのidなりuriを渡して、コンポーネント内と通信する必要が出てきます。前者は、member-listのカプセル化が不完全になるので不適切なケースが多く、後者は必要なことはあるけど面倒です。なので、結局は配列かオブジェクトを渡す必要が出てきます。

※要素数は可変なので、一人ずつ属性をつくって渡すのはナシです、念のため。

<member-list members={ members }></member-list>

<script>
  var this.members = [
    { name: 'John' },
    { name: 'Sean' },
    { name: 'Becky' },
    { name: 'Taro' }
  ]
</script>

こう書けると、ほっとするほど自然ですね。

属性として関数を渡す

ReactやRiotの革命的に便利だったのは、この点です(大げさかも)。見た目上は、HTMLにインラインスクリプトとして、

<button onlick="alerat(message)">Click me!</button>

とか書いているように見せかけて、その実、DOMのイベントハンドラに登録するというアレです。これのおかげで、

  • ある人は「jQueryは死んだ」
  • ある人は「コード量が一桁減った」

と言ったとか言わないとか。

独自タグ(コンポーネント)に属性を渡す場合は、イベントハンドラというよりは、コールバックに近いイメージかもしれません。たとえば、削除ロジックを子要素ではなく親要素に持たせるケースなど。

<task-list>
  <task-item remove={ remove }></task-item>
  <task-item remove={ remove }></task-item>
</task-list>

<task-item>
  <span>{ task }</span>
  <button onclick={ removeMe }> X </button>
  <script>
    removeMe (e) {
      opts.remove()
    }
  </script>
</task-item>

いくつかの例外

Riot.js特有の話になります。必ず属性にng-をつけたAngularJSと異なり、Riot.jsでは、属性はHTMLのもともとの属性を使います。それだと支障のある要素については、コンパイルの段階で別名に置き換えるという手をとっています。

イメージタグ

Riot.jsの実装だと、一時的にテンプレートがDOMに出力されます。存在しないアドレス({ url })にリクエストが行ってしまうとまずいので、コンパイルの時点で一時的にriot-srcに書き換えられます。

  • TAGファイル: <img src={ url }>
  • コンパイル後: <img riot-src={ url }>
  • DOM(評価後): <img src="path/to/somewhere">

インラインスタイル

これも同様の理由で、riot-styleに置き換えられます。

  • TAGファイル: <div style={ url }>
  • コンパイル後: <div riot-style={ url }>
  • DOM(評価後): <div style="color: red">

そのほか

2.0.12以降、driot-dになります。SVGで、<svg d="hoge">で使うため。(他にももう少し増えそうな予感)

まとめ

るほどのことはありません。最後に、むしろこれが書きたかった「属性変換の一覧」を載せておきます。Riot.jsを深く知りたい方へ。(といってもコード短いので、安心してどっぷり行きましょう。底は浅いです)

付録: Riot.jsの属性変換一覧表

タイプ .tag コンパイル後 DOM(評価後) DOMの値の例
画像Url src riot-src src 'images/logo.svg'
インラインスタイル style riot-style style 'color:red'
真偽値属性 checked
disabled
selected
...
__checked
__disabled
__selected
...
checked
disabled
selected
...
'checked'
'disabled'
'selected'
...
String foo foo foo 'bar'
Bool foo foo foo 'true''false'
※Stringに変換
Function foo foo イベントハンドラ 関数
Object/Array foo foo n/a ※削除される

※いずれの場合も、独自タグ(コンポーネント)であれば、その内部からopts.srcやらopts.style、opts.fooなどで元々の値を参照できます。

16
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
15