OWNED MEDIAウェブ制作に役立つコンテンツを発信中!

Vue.jsでslotを使って子コンポーネントを継承するレイアウトを作成してみる

デザインによっては大枠のレイアウトが共通となって、その内部がページごとに個別のスタイルを持っているというケースもあります。PugやLaravelのHTMLテンプレートであるBladeではextendという形で、別ファイルのHTMLを継承する形でインクルードすることができます。(参考記事「Pugでページテンプレートの作成にextendsとblockを活用する」)Vue.jsでも同じような形で、別コンポーネントのHTMLを「slot」という機能を使ってインポートすることで実現できます。   最初はslotを理解するのは少し難しいのですが、サンプルを例に見ていきます。まず親コンポーネントとなるページコンポーネント内で下記の構成があったとします。content-wrapperとcontent-innerのclassが付いている要素がページ共通のレイアウトで、その中にページごとに異なるコンテンツが入るという想定です。 【index.vue】
<template>
  <section class="content-section">

    <!-- 共通レイアウト -->
    <div class="content-wrapper">
      <div class="content-inner">

        <!-- 個別のコンテンツ -->
        <div class="content"></div>
        <div class="content"></div>
        <div class="content"></div>
        <!-- 個別のコンテンツ -->

      </div>
    </div>
    <!-- 共通レイアウト -->

  </section>
</template>
  上記の通り、共通のレイアウトになるので別コンポーネントとして切り分けます。共通となる部分のHTMLだけ切り分けられます。 【ContentWrapperComponent.vue】
<template>
  <div class="content-wrapper">
    <div class="content-inner">
    </div>
  </div>
</template>
  そして親コンポーネントとなるページコンポーネント側で切り分けた子コンポーネントをテンプレート内にインポートします。その中にページごとに異なるコンテンツが入るということですので、このような形になると思われますが、、 【index.vue】
<template>
  <section class="content-section">
    <content-wrapper-component>
      <div class="content"></div>
      <div class="content"></div>
      <div class="content"></div>
    </content-wrapper-component>
  </section>
</template>
  上記のように記述した場合、出力結果はこのようになり、子コンポーネントのHTMLは表示されるものの、親コンポーネント側で記述した子コンポーネント内に含まれるコンテンツが出力されません。当然ですが、子コンポーネント内で記述するか、別コンポーネントとしてインポートする必要があるということですね。 【HTML】
<section class="content-section">
  <div class="content-wrapper">
    <div class="content-inner"></div>
  </div>
</section>
  ただし、そうすると汎用的に使えなくなったり、コンテンツ専用のコンポーネントを作成しないといけなくなるため、本末転倒な結果になってしまいます。そこで、slotの出番となります。   slotの使い方ですが、まずは子コンポーネント側で対象となる部分をslot要素に置き換えます。このslotで置き換えた部分が親コンポーネント側で継承される形になります。slot要素には親コンポーネント側で指定できるようにするため、name属性で名前をつけておきます。 【ContentWrapperComponent.vue】
<template>
  <div class="content-wrapper">
    <slot name="content-inner-slot"></slot>
  </div>
</template>
  続いて親コンポーネント側では、出力される部分へtemplate要素を追加し「v-slot」ディレクティブで、子コンポーネントにあるslot要素をname属性の値で指定します。そして、その中に共通部分の中に含まれるコンテンツを通常通り記述していきます。 【index.vue】
<template>
  <section class="content-section">
    <content-wrapper-component>
      <template class="content-inner" v-slot:content-inner-slot>
        <div class="content"></div>
        <div class="content"></div>
        <div class="content"></div>
      </template>
    </content-wrapper-component>
  </section>
</template>
  こうすることで、当初想定していた形で出力されるようになりました。子コンポーネント内に含まれる内容を親コンポーネント側で記述したい場合には、子コンポーネントにslotを埋め込む必要がありますね。 【HTML】
<section class="content-section">
  <div class="content-wrapper">
    <div class="content-inner">
      <div class="content"></div>
      <div class="content"></div>
      <div class="content"></div>
    </div>
  </div>
</section>
 
  Vue.jsなどのフレームワークでHTMLを構成する場合に、共通部分はコンポーネントとして切り分けられる場面は多々ありますが、ページの大枠のレイアウトなどでHTMLをコンポーネント内で継承したい場合には必須となりますので、ぜひ覚えておきたいですね。
  • はてなブックマーク
  • Pocket
  • Linkedin
  • Feedly

この記事を書いた人

Twitter

SPONSORED

    KEYWORD SEARCH

    RECENT POSTS

    合同会社デザインサプライ -DesignSupply. LLC-

    サイト制作・開発 / 各種デザイン制作 / ウェブプロモーション企画

    合同会社デザインサプライ(DesignSupply. LLC)

    Office:大阪府大阪市天王寺区清水谷町3-22
    Email:info@designsupply-web.com
    • Twitter
    • Github
    CONTACT USSCROLL TO TOP
      • Facebook
      • Twitter
      • Github
      • Instagram