1分でわかるVue.jsのslotの使い方(サンプル付き)

Vue.jsのslotはわかりづらい

Vue.jsを使用しているとslotを使用する機会が必ずあるのだが、初心者だとこのslotの仕組みはわかりづらい。

Vue.js公式リファレンスの説明には…

Vueは現在のWeb Components spec draftにならったコンテンツ配信APIが実装されており、 <slot> 要素をコンテンツ配信の受け渡し口として利用します。

これを使うことで次のようなコンポーネントを作成することが出来ます

<navigation-link url="/profile">
  Your Profile
</navigation-link>

<a
  v-bind:href="url"
  class="nav-link"
>
  <slot></slot>
</a>

…このようにWeb Componentsを知っている前提で説明されているため、Web Componentsを知らなければ理解しにくい。

ちなみにWeb Componentsでslotを記述すると、このようになる。

Web Components sample

slotとはテンプレートタグ内の入れ替え

「slotとはテンプレートタグ内の文字列をslotタグへ入れ替えること」と覚えると理解しやすい。

例えばこのようにテンプレートを記述すれば名前は「鈴木」になるが…

<div id="app">
  <my-name></my-name>
</div>
Vue.component('my-name', {
  template: '<div>私の名前は鈴木です。</div>'
});
new Vue({
  el: '#app'
});

Vue.js slot sample 1

このように名前部分をslotタグで囲んでmy-nameタグの内側に「佐藤」を入れると「鈴木」が「佐藤」に入れ替わる。

<div id="app">
  <my-name>佐藤</my-name>
</div>
Vue.component('my-name', {
  template: '<div>私の名前は<slot>鈴木</slot>です。</div>'
});
new Vue({
  el: '#app'
});

Vue.js slot sample 2

slotはテンプレート内で複数使用可能

slotはslot属性とname属性を使用することで複数使用することができる。

<my-name>
  <h1 slot="header">ヘッダー</h1>
  <strong>佐藤</strong>
  <h2 slot="footer">フッター</h2>
</my-name>
Vue.component('my-name', {
  template: `
<div>
  <header><slot name="header"></slot></header>
  <main>私の名前は<slot>鈴木</slot>です。</main>
  <footer><slot name="footer"></slot></footer>
</div>`
});
new Vue({
  el: '#app'
});

Vue.js slot sample 3

ただし、テンプレートタグ内にインライン要素があると前後に半角スペースが表示されてしまうため、この場合はテンプレートタグ内に改行コードは入れず1行にまとめたほうが良い。

<my-name>
  <h1 slot="header">ヘッダー</h1><strong>佐藤</strong><h2 slot="footer">フッター</h2>
</my-name>

Vue.js slot sample 4

name付きのslotタグに文字列は入れない

name属性が付いているslotタグの場合は文字列を入れても入れ替わる訳ではないので文字列は入れない。

Vue.component('my-name', {
  template: `
<div>
  <header><slot name="header">頭</slot></header>
  <main>私の名前は<slot>鈴木</slot>です。</main>
  <footer><slot name="footer">足</slot></footer>
</div>`
});
new Vue({
  el: '#app'
});

Vue.js slot sample 5

slot-scopeで値を渡す

name属性が付いているslotタグで値を渡したい場合はslot-scopeを使用する。

<div id="app">
  <my-name>
    <h1 slot="header" slot-scope="p">ヘッダー {{ p.text }}</h1>
    <strong>佐藤</strong>
    <h2 slot="footer" slot-scope="p">フッター {{ p.text }}</h2>
  </my-name>
</div>
Vue.component('my-name', {
  template: `
<div>
  <header><slot name="header" text="頭"></slot></header>
  <main>私の名前は<slot>鈴木</slot>です。</main>
  <footer><slot name="footer" text="足"></slot></footer>
</div>`
});
new Vue({
  el: '#app'
});

Vue.js slot sample 6