LoginSignup
7
7

More than 3 years have passed since last update.

【Vue.js】slotの中身があるかないかv-ifで分岐する

Last updated at Posted at 2019-06-20

今後はv-slotを使いなさいって話のようで。

.section
    .section__header
        h2 ニュース
    .section__body
        ul
            li 

ヘッダーとボディーを持つセクションというのは、とてもよく使います。

.contents
    .section
    .section
    .section

のようにセクション単位でコンテンツを分けたりします。
「ひとかたまりのコンテンツはセクションで囲む」という鉄の掟を作ると、秩序が生まれます。
なのでコンポーネントを作り、これを使うことを遵守します。

/src/components/Section.vue
<template lang="pug">
    .section
        .header
            slot(name="header")
        .body
            slot(name="body")
</template>

単一ファイルコンポーネントとして作ります。
.section_headerとか.section_bodyとか書く必要も無くなるので、
クラス名を単純に.headerと.bodyにしてしまいます。
※pug-plain-loaderをインストールしているため、lang="pug"をつけることでPugの記法が使えるようになっています。

/src/views/Index.vue
<template lang="pug">
    Section
        template(v-slot:header)
            h2 新着ニュース一覧
        template(v-slot:body)
            ul
                li ...
                li ...
</template>
<script>
import Section from '@/components/Section.vue'
export default{
    components:{
        Section
    }
}
</script>

呼び出し元のViewです。
template(v-slot:header)の子要素がslot(name="header")に、
template(v-slot:body)の子要素がslot(name="body")に置きかわります。

記述する分量が増えてる疑惑がありますが、
クラス名が気に入らなくなって変えたいといった時でも
/src/components/Section.vueの1箇所を変えるだけで、
全てに適用されるのは魅力だと思います。
(パフォーマンスへの影響は若干気になるところですが)

さて、たまに厄介なのが、広告枠などheaderが要らないケースです。

    Section
        template(v-slot:body)
            iframe

のような場合です。
現状の/src/components/Section.vueは
template(v-slot:header)に子要素がなくても.headerを出力してしまいます。

    <div class="section">
        <div class="header"><div>
        <div class="body">
            <iframe></iframe>
        </div>
    </div>

といった具合に。
空のDOMエレメントが出力されてしまうのが気になるのでv-ifを使って
「template(v-slot:header)がない場合は.headerの部分を出力しない」
という分岐をします。

<template lang="pug">
    .section
        .header(v-if='this.$slots.header')
            slot(name="header")
        .body(v-if='this.$slots.body')
            slot(name="body")
</template>

のように「this.$slots」をv-ifの条件に使います。

/src/views/Index.vue
<template lang="pug">
    Section
        template(v-slot:body)
            iframe
</template>
<script>
import Section from '@/components/Section.vue'
export default{
    components:{
        Section
    }
}
</script>

すると、上記のようにtemplate(v-slot:body)がない場合は.headerが出力されなくなります。

7
7
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7