##はじめに
Vuejs は非常にとっつきやすく直感的に使える上に、多機能で大規模なサイトでも小規模なサイトでもスケールするJSフレームワークです。公式ドキュメントも充実しており、欲しいと思う情報や機能はほとんどそれだけでカバーすることが出来ます。
しかしながら多機能かつ柔軟性の高いフレームワークであるため、公式ドキュメントも肥大化しており、欲しい情報が見つけにくい!ということも当然あるため、ここに自分用に Vuejs のスロット機能の使い方についてメモっておきます。
##おしながき
- コンポーネント内で複数のスロットを指定したい(名前付きスロット)
- スロットのスコープについて
- スロット内にスロットの外から値を渡したい(スコープ付きスロット)
- スロットの名前を動的に変更したい(動的スロット)
- v-slot:とか書くのがめんどくさい(省略記法)
##名前付きスロット
コンポーネント内にスロットで置き換えたい箇所が1個所ならば通常のスロット配信(デフォルトスロット)で事足りるが、スロットで置き換えたい箇所が複数ある場合に使用する、ちなみに name のない slot は暗黙的に「default」という名前になっています。
例えば下記のような場合
<div class="content">
<header>
<slot name="head"></slot>
</header>
<p>これは共通で表示される</p>
<slot name="body"></slot>
</div>
<Wrapper>
<template v-slot:head>
<h1>HEAD</h1>
</template>
<template v-slot:body>
<div>BODY</div>
</template>
</Wrapper>
以下のように表示される
<div class="content">
<header>
<h1>HEAD</h1>
</header>
<p>これは共通で表示される</p>
<div>BODY</div>
</div>
上記の例のように、主に「スロットを使いたいんだけど、間にスロットで置き換えたくない要素がある」というような場合に有効。
v-slot 属性を名前なしで使用した場合には、前述のとおりデフォルトスロットに対するコンテンツであるとみなされます、また暗黙的にデフォルトスロットには「default」という名前になっているため v-slot:default
と指定した場合も同様にデフォルトスロットに適用されます。
参照:https://jp.vuejs.org/v2/guide/components-slots.html#名前付きスロット
##スロットのスコープについて
Vuejs のコンポーネント間のやり取りは、親からはprops、子からは$emitで値を渡すのが通常ですが、slotの場合は基本的にどちらも使えません。
従って、コンポーネント間のやりとりが必要な場合、slotに置き換えたために正常に動作しなくなるという可能性があります。
※これに対する最も安易な解決策はvuexを使うことだと思います。
参照:https://jp.vuejs.org/v2/guide/components-slots.html#コンパイルスコープ
##スコープ付きスロットという手段
とはいえ slot を指定している側から slot 内に値を渡すことは出来る、ここの説明は文章だと全く伝わらないので、
下記のコードを見てもらった方が理解が早いと思います。
<template>
<div class="parent">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'Wrapper',
data() {
return {
text: 'I am your father'/* これを slot 内で参照したい */
}
}
}
</script>
<MyComponent>
<template v-slot:default>
<div class="child">
<h1>これも表示させる</h1>
<!-- ここで親の値を参照したいが、以下のように単に text と書いても参照できない -->
<p>{{ text }}</p>
</div>
</template>
</MyComponent>
上記のような場合、下記のように記述することで子が親の data を参照できる。
ちょうどコンポーネントの props で親から子に値を渡すイメージで、この例では使用していないが分割代入を利用したり、
デフォルト引数を指定したりすることも可能です。
<template>
<div class="parent">
<slot :text="text"></slot> <!-- 親は普通にv-bindするだけ -->
</div>
</template>
<script>
export default {
name: 'Wrapper',
data() {
return {
text: 'I am your father'
}
}
}
</script>
<MyComponent>
<template v-slot:default="slotProps"><!-- スコープ付きスロットを指定 -->
<div class="child">
<h1>これも表示させる</h1>
<p>{{ slotProps.text }}</p> <!-- スコープ付きスロットにより渡された値を参照可能 -->
</div>
</template>
<MyComponent>
<div class="parent">
<div class="child">
<h1>これも表示させる</h1>
<p>I am your father</p>
</div>
</div>
参照:https://jp.vuejs.org/v2/guide/components-slots.html#スコープ付きスロット
参照:https://jp.vuejs.org/v2/guide/components-slots.html#スロットプロパティの分割代入
動的スロット
Vuejs 2.6.0より 動的引数というものがテンプレート構文に追加されています、これは Javascript の式をディレクティブの引数として利用できるというものですが、これをスロット名として利用することも出来ます。
<template v-slot:[dynamicSlotName]>
<p>どこかのスロットに適用される</p>
</template>
参照:https://jp.vuejs.org/v2/guide/components-slots.html#動的なスロット名
参照:https://jp.vuejs.org/v2/guide/syntax.html#動的引数
省略記法
Vuejs 2.6.0より v-slot:
を#
で記述することができます、具体的には下記のような書き方が可能です。
<Wrapper>
<template #head>
<h1>HEAD</h1>
</template>
<template #body>
<div>BODY</div>
</template>
</Wrapper>
参照:https://jp.vuejs.org/v2/guide/components-slots.html#名前付きスロットの省略記法