【vue】 slotでコンポーネントに要素を埋め込む

slotを用いると、子のコンポーネントに対し、親が任意のHTMLや値、コンポーネントなどを埋め込むことができます。

例えば、メッセージウィンドウを作成するときなどに便利です。

使い方

まずはコンポーネント側でslot枠<slot></slot>を用意します。

app.component("button-component", {
    // ...

    template: `
        <div style="border: 1px solid #000;">
            <p>slot開始</p>
            <slot></slot>
            <p>slot終わり</p>
        </div>
    `,
});

コンポーネントを呼び出す側では、タグの内側にslotに入れたい内容を書きます。

<div id="app">
    <button-component>
        <!-- slotに入れる内容 -->
        <p>Hello, slot World!!</p>
    </button-component>
</div>

そうすると、タグの中に書いた内容がコンポーネント側のslotの部分に出力されます。

See the Pen vue slot by Totori (@souki202) on CodePen.

もし, 呼び出し側でタグの中に何かを入力しても、コンポーネント側でslotがない場合は破棄されます。

デフォルトの内容設定

slotには、呼び出し側でslotの中身を設定しなかった場合に表示する内容を設定できます。

app.component("button-component", {
    // ...

    template: `
<div>
    <slot>
        <p>Hello, slot World!!</p>
    </slot>
</div>
    `,
});

呼び出し側でslotの中身を指定した場合、このデフォルト値から上書きされます。

注意点として, このデフォルトの中身はコンポーネント側で書いているため、そのコンポーネントの値やメソッドしか利用できません。

See the Pen by Totori (@souki202) on CodePen.

複数のslot

slotは複数用意できます。この場合、それぞれのslotに<slot name="header"></slot>のようにしてname属性をつけ、呼び出し側でどのslotに何を入れるかそれぞれ指定できます。

app.component("page-component", {
    data() {
        return {}
    },
    template: `
<div style="border: 1px solid #000;">
    <slot name="header"></slot>
    <slot name="main"></slot>
    <slot name="footer"></slot>
</div>
    `,
});
<page-component>
    <!-- <slot name="header></slot> に入る -->
    <template v-slot:header>
        <p>header</p>
    </template>

    <!-- <slot name="main></slot> に入る -->
    <template v-slot:main>
        <p>main contents</p>
    </template>

    <!-- <slot name="footer></slot> に入る -->
    <template v-slot:footer>
        <p>footer</p>
    </template>
</page-component>

See the Pen vue slot4 by Totori (@souki202) on CodePen.

v-slot:#と略せます。v-slot:headerは、#headerという書き方ができます。

nameを指定しなかったslotに入れたい場合、<template v-slot:default>...</template>とするとnameが無いslotに入ります。

値やメソッドを使う場合

slotの内容にdatamethodなどを使う場合、呼び出し側の値が使用されます。

例えば、

<button-component>
    <p>{{ msg }}</p>
    <button @click="onclick">メッセージ変更</button>
</button-component>

と書くと、クリック時に呼び出されるのはコンポーネントのonclickではなく、呼び出し側 (親) のonclickです。

See the Pen vue slot2 by Totori (@souki202) on CodePen.

子コンポーネント内の値を使用する

もしslotに設定する際に子のメソッドなどを使用したい場合、子から親に向かって値を受け渡すことで利用することができるようになります。

app.component("page-component", {
    data() {
        return {
            value: 100,
        }
    },
    template: `
<div style="border: 1px solid #000;">
    <slot :value="value"></slot>
</div>
    `,
});

このように、slot内で値をv-bindすることで渡し、

<div id="app">
    <!-- #defaultは名前がないslotの場合 -->
    <page-component #default="slotProps">
        {{ slotProps.value }}
    </page-component>
</div>

v-slot:slotname="props"で受け取り、{{ props.varname }}で利用します。複数受け渡す場合、v-bindを増やすだけです。

See the Pen by Totori (@souki202) on CodePen.

暗黙のslot

無名のslotにtemplateで囲まずに要素を入れた場合、裏で自動的にtemplateに囲まれます。つまり、

<button-component>
    <p>Hello, slot World!!</p>
</button-component>
<button-component>
    <template #default>
        <p>Hello, slot World!!</p>
    </template>
</button-component>

この2つは同じです。もしv-forなどをした場合、forした結果が囲まれます。

<button-component>
    <p v-for="i in 3">Hello, slot World!!</p>
</button-component>
<button-component>
    <template #default>
        <p v-for="i in 3">Hello, slot World!!</p>
    </template>
</button-component>

See the Pen vue slot6 by Totori (@souki202) on CodePen.

まとめ

slotを用いることで、子のコンポーネントに任意の表示内容を埋め込むことができます。コンポーネントには枠だけ用意しておいて、外からタイトルや説明文などをDOMで設定したい場合におすすめです。

vue slot thumb

役に立ったらシェアしよう!