導入
今日の話題はVue3で子エレメントの外側を別のエレメントでラップする方法についてです。
※ 私が株式会社愛宕 Advent Calendar 2023に書く記事は主に社内向けに共有しておきたいけど勉強会をするまでもないちょっとしたTipsにしたいと思います。
言葉で表すとわかりにくいのでコードを例示します。
次のような構造になるようなコンポーネントを作りたいとします。<div>hoge</div>
の部分は子エレメントとして用途に応じて差し替えるようにしたいです。
<div class="group">
<div class="group-item">
<div>hoge</div>
</div>
<div class="group-item">
<div>fuga</div>
</div>
<div class="group-item">
<div>piyo</div>
</div>
</div>
そこで、次のように書いてみることにします。Vue3のSFC(single file component)を想定しています。
app.vue
<template>
<ExampleGroup>
<div>hoge</div>
<div>fuga</div>
<div>piyo</div>
</ExampleGroup>
</template>
ExampleGroup.vue
<template>
<div class="group">
<div class="group-item">
<slot/>
</div>
</div>
</template>
と書いても当然、
<div class="group">
<div class="group-item">
<div>hoge</div>
<div>fuga</div>
<div>piyo</div>
</div>
</div>
となるだけで、目的の構造にはなりません。
子エレメントをそれぞれ分解してその一つ一つを別のエレメントでラップするにはどうすればいいでしょうか?
解決
slotの中のvnodeを取り出してv-for
でループします。取り出したvnodeは<component>
のis
に渡して描画しましょう。
ExampleGroup.vue
<template>
<div class="group">
<div class="group-item" v-for="vnode in $slots.default()>
<component :is="vnode"></component>
</div>
</div>
</template>
こうすることでslotに渡した子エレメント全てに<div class="group-item">
でラップすることができます。