ガイド
基本的な使い方
- インストール
- はじめに
- Vue インスタンス
- テンプレート構文
- 算出プロパティとウォッチャ
- クラスとスタイルのバインディング
- 条件付きレンダリング
- リストレンダリング
- イベントハンドリング
- フォーム入力バインディング
- コンポーネントの基本
コンポーネントの詳細
- コンポーネントの登録
- プロパティ
- カスタムイベント
- スロット
- 動的 & 非同期コンポーネント
- 特別な問題に対処する
トランジションとアニメーション
- Enter/Leave とトランジション一覧
- 状態のトランジション
再利用と構成
- ミックスイン
- カスタムディレクティブ
- 描画関数とJSX
- プラグイン
- フィルター
ツール
- 単一ファイルコンポーネント
- テスト
- TypeScript のサポート
- プロダクション環境への配信
スケールアップ
- ルーティング
- 状態管理
- サーバサイドレンダリング
- セキュリティ
内部
- リアクティブの探求
移行
- Vue 1.x からの移行
- Vue Router 0.7.x からの移行
- Vuex 0.6.x から 1.0 への移行
その他
- 他のフレームワークとの比較
- Vue.js コミュニティへ参加しましょう!
- チームに会おう
v2.x 以前のドキュメントです。 v3.x のドキュメントを見たい場合はこちら
スロット
最終更新日: 2019年2月20日
このページは コンポーネントの基本 を読まれていることが前提になっています。コンポーネントを扱った事のない場合はこちらのページを先に読んでください。
バージョン 2.6.0 で、名前付きスロットとスコープ付きスロットに対する新しい統一構文 (
v-slot
ディレクティブ) が導入されました。slot
およびslot-scope
属性は非推奨となり置き換えられますが、まだ削除は されず 、ドキュメントも ここ にあります。新しい構文を導入する理由は、この RFC に記述されています。
スロットコンテンツ
Vue には Web Components spec draft にヒントを得たコンテンツ配信 API が実装されており、 <slot>
要素をコンテンツ配信の受け渡し口として利用します。
これを使うことで次のようなコンポーネントを作成することが出来ます:
<navigation-link url="/profile">
Your Profile
</navigation-link>
そして、 <navigation-link>
のテンプレートはこうなります:
<a
v-bind:href="url"
class="nav-link"
>
<slot></slot>
</a>
コンポーネントを描画する時、 <slot></slot>
は「Your Profile」に置換されるでしょう。スロットには HTML を含む任意のテンプレートを入れることが出来ます:
<navigation-link url="/profile">
<!-- Font Awesome のアイコンを追加 -->
<span class="fa fa-user"></span>
Your Profile
</navigation-link>
または、他のコンポーネントを入れることも出来ます:
<navigation-link url="/profile">
<!-- コンポーネントを使ってアイコンを追加 -->
<font-awesome-icon name="user"></font-awesome-icon>
Your Profile
</navigation-link>
もしも <navigation-link>
のテンプレートが <slot>
要素を含ま ない 場合、開始タグと終了タグの間にある任意のコンテンツは破棄されます。
コンパイルスコープ
スロットの中でデータを扱いたい場合はこうします:
<navigation-link url="/profile">
Logged in as {{ user.name }}
</navigation-link>
このスロットは、テンプレートの残りの部分と同じインスタンスプロパティ (つまり、同じ “スコープ”) にアクセスできます。<navigation-link>
のスコープにアクセスすることは できません。例えば、url
へのアクセスは動作しないでしょう:
<navigation-link url="/profile">
Clicking here will send you to: {{ url }}
<!--
`url` は undefined になります。というのも、このコンテンツは
<navigation-link> コンポーネント _の中で_ 定義されるのではなく、
<navigation-link> コンポーネント _に_ 渡されるからです。
-->
</navigation-link>
ルールとしては、以下を覚えておいてください:
親テンプレート内の全てのものは親のスコープでコンパイルされ、子テンプレート内の全てのものは子のスコープでコンパイルされる。
フォールバックコンテンツ
スロットに対して、コンテンツがない場合にだけ描画されるフォールバック (つまり、デフォルトの) コンテンツを指定すると便利な場合があります。例えば、<submit-button>
コンポーネントにおいて:
<button type="submit">
<slot></slot>
</button>
ほとんどの場合には <button>
の中に「Submit」という文字を描画したいかもしれません。「Submit」をフォールバックコンテンツにするには、<slot>
タグの中に記述します。
<button type="submit">
<slot>Submit</slot>
</button>
そして、親コンポーネントからスロットのコンテンツを指定せずに <submit-button>
を使うと:
<submit-button></submit-button>
フォールバックコンテンツの「Submit」が描画されます:
<button type="submit">
Submit
</button>
しかし、もしコンテンツを指定すると:
<submit-button>
Save
</submit-button>
指定されたコンテンツが代わりに描画されます:
<button type="submit">
Save
</button>
名前付きスロット
2.6.0 から更新。
slot
属性を使った非推奨の構文については、こちらを参照
複数のスロットがあると便利なときもあります。例えば、<base-layout>
コンポーネントが下記のようなテンプレートだとしましょう:
<div class="container">
<header>
<!-- ここにヘッダコンテンツ -->
</header>
<main>
<!-- ここにメインコンテンツ -->
</main>
<footer>
<!-- ここにフッターコンテンツ -->
</footer>
</div>
こういった場合のために、 <slot>
要素は name
という特別な属性を持っていて、追加のスロットを定義できます:
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
name
のない <slot>
要素は、暗黙的に「default」という名前を持ちます。
名前付きスロットにコンテンツを指定するには、<template>
に対して v-slot
ディレクティブを使って、スロット名を引数として与えます:
<base-layout>
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<template v-slot:footer>
<p>Here's some contact info</p>
</template>
</base-layout>
これにより、<template>
要素の中身はすべて対応するスロットに渡されます。v-slot
を使った <template>
で囲まれていないコンテンツは、デフォルトスロットに対するものだとみなされます。
しかし、明示的に指定したいなら、デフォルトスロットのコンテンツを <template>
で囲むこともできます:
<base-layout>
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<template v-slot:default>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</template>
<template v-slot:footer>
<p>Here's some contact info</p>
</template>
</base-layout>
いずれにせよ、描画される HTML は次のようになります:
<div class="container">
<header>
<h1>Here might be a page title</h1>
</header>
<main>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</main>
<footer>
<p>Here's some contact info</p>
</footer>
</div>
非推奨になった slot
属性 とは異なり、v-slot
は <template>
だけに追加できる (1つだけ例外 あり) 点に注意してください。
スコープ付きスロット
2.6.0 から更新。
slot-scope
属性を使った非推奨の構文については、こちらを参照
スロットコンテンツから、子コンポーネントの中だけで利用可能なデータにアクセスできると便利なことがあります。例えば、以下のようなテンプレートの <current-user>
コンポーネントを考えてみてください:
<span>
<slot>{{ user.lastName }}</slot>
</span>
ここで、ユーザーの名字の代わりに名前を表示するよう、このフォールバックコンテンツを置き換えたいと思うかもしれません:
<current-user>
{{ user.firstName }}
</current-user>
しかし、これは動作しません。というのも、user
にアクセスすることができるのは <current-user>
コンポーネントだけですが、ここで指定しているコンテンツは親コンポーネントで描画されるからです。
親コンポーネント内でスロットコンテンツとして user
を使えるようにするためには、<slot>
要素の属性として user
をバインドします:
<span>
<slot v-bind:user="user">
{{ user.lastName }}
</slot>
</span>
<slot>
要素にバインドされた属性は、スロットプロパティ と呼ばれます。親スコープ内で v-slot
の値として名前を指定することで、スロットプロパティを受け取ることができます:
<current-user>
<template v-slot:default="slotProps">
{{ slotProps.user.firstName }}
</template>
</current-user>
この例では、すべてのスロットプロパティを保持するオブジェクトの名前を slotProps
にしましたが、あなたの好きな名前を使うことができます。
デフォルトスロットしかない場合の省略記法
上の例のようにデフォルトスロット だけの 場合は、コンポーネントのタグをスロットのテンプレートとして使うことができます。つまり、コンポーネントに対して v-slot
を直接使えます。
<current-user v-slot:default="slotProps">
{{ slotProps.user.firstName }}
</current-user>
さらに短くすることもできます。未指定のコンテンツがデフォルトスロットのものとみなされるのと同様に、引数のない v-slot
もデフォルトコンテンツを参照しているとみなされます:
<current-user v-slot="slotProps">
{{ slotProps.user.firstName }}
</current-user>
デフォルトスロットに対する省略記法は、名前付きスロットと混在させることが できない 点に注意してください。スコープの曖昧さにつながるためです:
<!-- 不正。警告が出る -->
<current-user v-slot="slotProps">
{{ slotProps.user.firstName }}
<template v-slot:other="otherSlotProps">
slotProps is NOT available here
</template>
</current-user>
複数のスロットがある場合は常に すべての スロットに対して <template>
ベースの構文を使用してください:
<current-user>
<template v-slot:default="slotProps">
{{ slotProps.user.firstName }}
</template>
<template v-slot:other="otherSlotProps">
...
</template>
</current-user>
スロットプロパティの分割代入
内部的には、スコープ付きスロットはスロットコンテンツを単一引数の関数で囲むことで動作させています。
function (slotProps) {
// ... slot content ...
}
これは、v-slot
の値が関数定義の引数部分で有効な任意の JavaScript 式を受け付けることを意味します。そのため、サポートされている環境 (単一ファイルコンポーネント または モダンブラウザ) では、特定のスロットプロパティを取得するために ES2015 の分割代入 を使うこともできます:
<current-user v-slot="{ user }">
{{ user.firstName }}
</current-user>
こうするとテンプレートはよりきれいになります。特に、スロットが多くのプロパティを提供している場合はそうです。また、プロパティをリネームする (例えば、user
から person
) など別の可能性も開けます:
<current-user v-slot="{ user: person }">
{{ person.firstName }}
</current-user>
スロットプロパティが未定義だった場合のフォールバックを定義することさえできます:
<current-user v-slot="{ user = { firstName: 'Guest' } }">
{{ user.firstName }}
</current-user>
動的なスロット名
2.6.0 で新規追加
ディレクティブの動的引数 は v-slot
でも動作し、動的なスロット名の定義が可能です:
<base-layout>
<template v-slot:[dynamicSlotName]>
...
</template>
</base-layout>
名前付きスロットの省略記法
2.6.0 で新規追加
v-on
や v-bind
と同様に v-slot
にも省略記法があり、引数の前のすべての部分 (v-slot:
) を特別な記号 #
で置き換えます。例えば、v-slot:header
は #header
に書き換えることができます:
<base-layout>
<template #header>
<h1>Here might be a page title</h1>
</template>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<template #footer>
<p>Here's some contact info</p>
</template>
</base-layout>
しかし、ほかのディレクティブと同様に、省略記法は引数がある場合にのみ利用できます。これは、次のような構文が不正ということを意味します:
<!-- これは警告を引き起こす -->
<current-user #="{ user }">
{{ user.firstName }}
</current-user>
代わりに、省略記法を使いたい場合には、常にスロット名を指定する必要があります:
<current-user #default="{ user }">
{{ user.firstName }}
</current-user>
その他の例
スロットプロパティを使えば、入力プロパティに応じて異なるコンテンツを描画する再利用可能なテンプレートにスロットを変えることができます。 これは、データロジックをカプセル化する一方で親コンポーネントによるレイアウトのカスタマイズを許すような、再利用可能なコンポーネントを設計しているときに特に便利です。
例えば、リストのレイアウトと絞り込みロジックを含む <todo-list>
コンポーネントを実装しているとします:
<ul>
<li
v-for="todo in filteredTodos"
v-bind:key="todo.id"
>
{{ todo.text }}
</li>
</ul>
それぞれの todo に対するコンテンツをハードコーディングする代わりに、todo ごとにスロットを作成し、スロットプロパティとして todo
をバインドすることで、親コンポーネントから制御できるようにします:
<ul>
<li
v-for="todo in filteredTodos"
v-bind:key="todo.id"
>
<!--
それぞれの todo のためのスロットがあり、 `todo` オブジェクトを
スロットのプロパティとして渡している
-->
<slot name="todo" v-bind:todo="todo">
<!-- フォールバックコンテンツ -->
{{ todo.text }}
</slot>
</li>
</ul>
この <todo-list>
コンポーネントを利用する時、子からのデータにはアクセスしながらも、todo アイテムに対して代わりの <template>
を定義することができます:
<todo-list v-bind:todos="todos">
<template v-slot:todo="{ todo }">
<span v-if="todo.isComplete">✓</span>
{{ todo.text }}
</template>
</todo-list>
しかし、これでもスコープ付きスロットが可能にすることの表面を走り書きした程度にすぎません。実世界の強力な利用例については、Vue Virtual Scroller や Vue Promised, Portal Vue といったライブラリを見てみることをおすすめします。
非推奨の構文
Vue 2.6.0 で
v-slot
ディレクティブが導入され、まだサポートされているもののslot
およびslot-scope
属性に代わる改善された API を提供しています。v-slot
を導入する理由は、この RFC に完全に記述されています。slot
およびslot-scope
属性は今後の 2.x リリースで引き続きサポートされますが、公式に非推奨となり、Vue 3 では削除されるでしょう。
slot
属性による名前付きスロット
2.6.0 以降では 非推奨。推奨される新しい構文については、こちら を参照。
親から名前付きスロットにコンテンツを渡すには、<template>
に対して特別な slot
属性を使います (例として、ここ で説明した <base-layout>
コンポーネントを使用):
<base-layout>
<template slot="header">
<h1>Here might be a page title</h1>
</template>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<template slot="footer">
<p>Here's some contact info</p>
</template>
</base-layout>
あるいは、slot
属性を通常の要素に直接指定することもできます:
<base-layout>
<h1 slot="header">Here might be a page title</h1>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<p slot="footer">Here's some contact info</p>
</base-layout>
名前のないスロットは デフォルトスロット となり、スロットの指定がないコンテンツをすべて受け取ります。上のどちらの例も、描画される HTML は次のようになります:
<div class="container">
<header>
<h1>Here might be a page title</h1>
</header>
<main>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</main>
<footer>
<p>Here's some contact info</p>
</footer>
</div>
slot-scope
属性によるスコープ付きスロット
2.6.0 以降では 非推奨。推奨される新しい構文については、こちら を参照。
スロットに渡されたプロパティを受け取るには、親コンポーネントは <template>
に対して slot-scope
属性を使えます (例として、ここ で説明した <slot-example>
を使用):
<slot-example>
<template slot="default" slot-scope="slotProps">
{{ slotProps.msg }}
</template>
</slot-example>
ここで、slot-scope
はプロパティを受け取るオブジェクトを slotProps
変数として宣言し、<template>
の中で利用できるようにしています。JavaScript の関数引数の名前と同じように、slotProps
の代わりに好きな名前を使うことができます。
slot="default"
は省略することもできます:
<slot-example>
<template slot-scope="slotProps">
{{ slotProps.msg }}
</template>
</slot-example>
slot-scope
属性は、<template>
要素以外 (コンポーネントも含む) に対して直接指定することもできます:
<slot-example>
<span slot-scope="slotProps">
{{ slotProps.msg }}
</span>
</slot-example>
slot-scope
の値は、関数定義の引数部分で有効な任意の JavaScript 式を受け付けることができます。これは、サポートされている環境 (単一ファイルコンポーネント または モダンブラウザ) では、式に ES2015 の分割代入 が使えることを意味します:
<slot-example>
<span slot-scope="{ msg }">
{{ msg }}
</span>
</slot-example>
ここ で説明した <todo-list>
を例にすると、slot-scope
で同等のことをするには次のようにします:
<todo-list v-bind:todos="todos">
<template slot="todo" slot-scope="{ todo }">
<span v-if="todo.isComplete">✓</span>
{{ todo.text }}
</template>
</todo-list>