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


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

- React
- Polymer
- Riot.js

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

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

## 複数の属性を渡すとき

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

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

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

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

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

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

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

## 配列を属性として渡す

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

```html
<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`のカプセル化が不完全になるので不適切なケースが多く、後者は必要なことはあるけど面倒です。なので、結局は配列かオブジェクトを渡す必要が出てきます。

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

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

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

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

## 属性として関数を渡す

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

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

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

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

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

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

```html
<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以降、`d`も`riot-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`<br>`disabled`<br>`selected`<br>... | `__checked`<br>`__disabled`<br>`__selected`<br>... | `checked`<br>`disabled`<br>`selected`<br>... | `'checked'`<br>`'disabled'`<br>`'selected'`<br>...
String | `foo` | `foo` | `foo` | `'bar'`
Bool | `foo` | `foo` | `foo` | `'true'` か `'false'`<br>※Stringに変換
Function | `foo` | `foo` | イベントハンドラ | 関数
Object/Array | `foo` | `foo` | n/a | ※削除される

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