親側から子コンポーネントにテンプレートの一部を差し込める、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
コメントが承認されるまで時間がかかります。