以下のような table を作りたい場合、React の Fragment に類する要素が必要となる。
https://reactjs.org/docs/fragments.html
<table>
<tbody>
<React.Fragment v-for="item in items">
<tr>
<td>{{item.name}}</td>
</tr>
<tr v-if="item.children">{{item.children.name}}</tr>
</React.Fragment>
</tbody>
</table>
なぜならば、table の仕様上、tbody 等(thead, tfooter) の直下には div などの要素はおいてはいけないからだ。(基本は tr がくるので) つまり以下のようにはできない。このようにした場合、table の挙動が保証されない。
<table>
<tbody>
<div v-for="item in items">
<tr>
<td>{{item.name}}</td>
</tr>
<tr v-if="item.children">{{item.children.name}}</tr>
</div>
</tbody>
</table>
vue には react の fragment に相当する要素がない
しかし Vue にはそれに相当する要素がない。(一時期あったバージョンもあるようだが)
解決策としては functional component 等が提案されているようだが、シンプルに fragment に類するコンポーネントを使いたい。
一応サードパーティ製のものがある
https://www.npmjs.com/package/vue-fragments
開発メンテが終了しているが、一応コンポーネントとしてある。
ただし、import 時の挙動がドキュメントとあっていなかったので、修正したものを個人的に公開した。本プロジェクトはメンテナンスをしていないようで、プルリクが通らないため。
使い方
npm i @superyusuke/vue-fragment
<template>
<v-fragment>2</v-fragment>
</template>
<script>
import { VFragment } from '@superyusuke/vue-fragment'
export default {
components: { VFragment }
}
</script>
注意
ただし、本家が Fragment を採用していない理由はなにかあるはずなので、このコンポーネントは何らかの問題を抱えている可能性がある。とくにパフォーマンスに関して、あまり高くないかもしれない。使わなくていい場合には使わない方がいいと思われる。
table を使うのをやめた
ただ、最終的には table を使用するのをやめようと今検討して動いている。table は高さの縦のラインが揃うことが利点だが、反面、スタイリングの自由度は低い。ほかのフロントエンドエンジニアに相談したところ、CSS Grid を使うのがよいのではないか、という結論に至った。IE 11 にも autoprefixer が対応させてくれる。