親側から子コンポーネントにテンプレートの一部を差し込める、slotという機能を使ってみます。
サンプルコード
navigation-linkという名前のコンポーネントを作成してみます。
Vue.component('navigation-link', { props: ['url'], template: ` <a v-bind:href="url" class="nav-link" > <slot>指定がなかった場合の初期値</slot> </a> ` }); var app = new Vue({ el: '#app', });
8行目のslot部分が、コンポーネント使用時に設定する内容で置き換えることができます。
コンポーネント使用時に設定がなかった場合は、slotタグ内の記述内容(今回の場合は「指定がなかった場合の初期値」)が表示されます。
実際にコンポーネントを使ってみます。
<div id="app"> <navigation-link url="/profile"> <span>プロフィール</span> </navigation-link> <navigation-link url="/user"></navigation-link> </div>
navigation-linkタグの中に記述した内容が前述のslotタグ部分と置き換わって描画されます。
slotのデモページ
slotを同一コンポーネント内で複数使用したい場合、name属性を使って名前を付けることができます。
Vue.component('base-layout', { template: ` <div class="container"> <header> <slot name="header"></slot> </header> <main> <slot></slot> </main> <footer> <slot name="footer"></slot> </footer> </div> ` }); var app = new Vue({ el: '#app' });
name属性のないslot(8行目)はdefaultという名前になります。
コンポーネント使用時は、templateタグに「v-slot:スロット名」の形で指定します。
<div id="app"> <base-layout> <template v-slot:header> <h1>ヘッダー</h1> </template> <p>コンテンツ部分</p> <template v-slot:footer> <p>フッター</p> </template> </base-layout> </div>
templateタグで囲っていない部分はdefaultになります。
名前付きslotのデモページ
slotの内容指定の際、親側のデータを指定することもできます。
<div id="app"> 未設定時: <current-user></current-user> 親側のデータ指定: <current-user> <template> {{ name }} </template> </current-user> </div>
JavaScript側の設定です。
Vue.component('current-user', { data: function () { return { user: { firstName: 'taro', lastName: 'suzuki' } } }, template: ` <span> <slot> {{ user.lastName }} </slot> </span> ` }); var app = new Vue({ el: '#app', data: { name: 'tanaka' } });
ただ逆に、親側からコンポーネント内のデータにアクセスすることは通常できません。
<div id="app"> <current-user> <template> {{ user.firstName }} </template> </current-user> </div>
スコープ付きスロットという機能を使うことで、コンポーネント内のデータにアクセスできます。
使用したいデータ(今回の場合user)をslotタグの属性としてバインドします。
Vue.component('current-user', { data: function () { return { user: { firstName: 'taro', lastName: 'suzuki' } } }, template: ` <span> <slot v-bind:user="user"> {{ user.lastName }} </slot> </span> ` }); var app = new Vue({ el: '#app', data: { name: 'tanaka' } });
templateタグで以下ように設定すると、子コンポーネントのデータを親で使用できます。
<div id="app"> <current-user> <template v-slot:default="slotProps"> {{ slotProps.user.firstName }} </template> </current-user> </div>
slotProps部分はほかの名前でも大丈夫です。
スコープのデモページ3
コメントが承認されるまで時間がかかります。