BETA

UdemyのVue JS講座を受講した際のメモ その4

投稿日:2020-04-29
最終更新:2020-04-29

slotについて

slotタグを使うことによって、親コンポーネントから子コンポーネントに、html形式のデータを送ることができる。
親コンポーネントでは、子コンポーネントのタグの中に送りたいhtml形式のデータを書く。
子コンポーネントでは、<slot></slot>を記述することによって、その場所に上記のデータが展開される。(templateタグ内には1つの親要素しか書けないという制約があるため、divで囲む)
この際、<slot></slot>に展開される文のスコープは、親コンポーネントに限る。
ただし、スタイルは親・子どちらに書いても適用される。どちらにもスタイルを書いた場合は、親が勝つ。
v-slot:hoge#hogeに置き換えられる。

<!-- 親コンポーネント -->  
<template>  
    <HogeComponent>  
        <h1>合計数:</h1>  
        <p>{{number}}</p> <!-- 親コンポーネントのnumberを参照する。 -->  
    </HogeComponent>  
</template>  

<!-- 子コンポーネントHogeComponent -->  
<template>  
  <div>  
    <slot></slot>  
  </div>  
</template>  

フォールバックコンテンツ

親コンポーネントで子コンポーネントを使う際、タグの中に何も書かない場合にかぎり、フォールバックコンテンツが利用できる。
フォールバックコンテンツは、slotタグの中に書く。

<!-- 親コンポーネント -->  
<template>  
    <HogeComponent></HogeComponent> <!-- タグの中に何も書かない -->  
</template>  

<!-- 子コンポーネントHogeComponent -->  
<template>  
  <div>  
    <slot>  
       <h1>フォールバックコンテンツ</h1> <!-- これが表示される -->  
    </slot>  
  </div>  
</template>  

slotって複数使えるの?

使える。<slot></slot>を複数書くと、同じ内容のものがslotの数だけ並ぶ。

複数slotを使ってそれぞれに違う内容を表示したい場合は?

v-slotディレクティブを使えば可能。
親コンポーネントでは、送りたいタグをtemplateタグで囲み、v-slot:{任意の名前}属性を追加する。(v-slotとtemplateはセットで使う。divではだめ。)
子コンポーネントでは、受け取りたいデータの名前(v-slot:のあとにつけた名前)を、name属性としてslotタグに追加する。
名前付きslot と呼ぶ。

<!-- 親 -->  
<template>  
  <div>  
    <ChildComponent>  
       <template v-slot:title>  
         <h1>タイトルです</h1>  
       </template>  
       <template v-slot:number>  
         <p>{{number}}</p>  
       </template>  
    </ChildComponent>  
  </div>  
</template>  

<!-- 子 -->  
<template>  
  <div>  
    <slot name="title"></slot>  
    <hr>  
    <slot name="number"></slot>  
  </div>  
</template>  

デフォルトスロット

子コンポーネントのタグの中で、templateタグで囲っていない部分はすべてデフォルトスロットになる。
デフォルトスロットは、子コンポーネントにおいて、<slot></slot>で受け取れる。
内部的には、templateタグがついてない部分を集めて、名前がdefaultの名前付きスロットを作成している。
そのため、templateタグをまたいで他のタグがある場合などは、表示の順番が変わる。

<!-- ParentComponent -->  
<template>  
  <div>  
    <child-component>  
      <p>1: default-slot</p>  
      <template v-slot:slot-2>  
        <p>2: slot-2</p>  
      </template>  
      <p>3: default-slot</p>  
      <template v-slot:slot-4>  
        <p>4: slot-4</p>  
      </template>  
      <p>5: default-slot</p>  
    </child-component>  
  </div>  
</template>  

<!-- ChildComponent -->  
<template>  
  <div>  
    <slot></slot>  
    <slot name="slot-2"></slot>  
    <slot name="slot-4"></slot>  
  </div>  
</template>  

結果

1: default-slot  
3: default-slot  
5: default-slot  
2: slot-2  
4: slot-4  

スロットプロパティ

slotを利用する際、どうしても子コンポーネントの値を参照したい場合は、スロットプロパティで実現できる。
(あんまり使わないらしい。)
子コンポーネントでは、slotに:{任意の名前(hoge)}="{渡したいdataの名前}"属性を追加する。
親コンポーネントでは、v-slot:{スロットの名前}="{任意の名前(slotProps)}"とする。
すると、slotProps.hogeで渡したいデータにアクセスすることができる。

<!-- ChildComponent.vue -->  
<template>  
  <div>  
    <slot name="user" :hoge="user"></slot>  
  </div>  
</template>  

<script>  
export default {  
  data() {  
    return {  
      user: {  
        firstName: "Hanako",  
      }  
    }  
  }  
}  
</script>  
<!-- App.vue -->  
<template>  
  <div>  
    <child-component>  
      <template v-slot:user="slotProps">  
      <h1>{{ slotProps.hoge }}</h1>  
      <h2>{{ slotProps.hoge.firstName }}</h2>  
      <hr>  
      <h1>{{ parentName }}</h1>  
    </template>  
    </child-component>  
  </div>  
</template>  

<script>  
import ChildComponent from "./components/ChildComponent.vue";  

export default {  
  name: "App",  
  data() {  
    return {  
      parentName: "Taro"  
    }  
  },  
  components: {  
    ChildComponent  
  }  
};  
</script>  

動的に表示するコンポーネントを切り替える

動的にコンポーネントを切り替えるためには、componentタグを使う。
<component :is="コンポーネントの名前"とすると、指定したコンポーネントが表示される。
コンポーネントの名前を動的に変更すれば、表示されるコンポーネントも動的に切り替わる。
注意点として、コンポーネントが切り替わるたびにインスタンスが削除・生成されるため状態を保持できない。
componentタグをkeep-aliveタグで囲めば状態を保持できるようになる。
keep-aliveタグを使うと、activateddeactivatedという2つのライフサイクルが追加される。

<template>  
  <div>  
    <child-component>  
      <p>はじめまして</p>  
    </child-component>  
    <button @click="currentComponent = 'Home'">Home</button>  
    <button @click="currentComponent = 'About'">About</button>  
    <component :is="currentComponent"></component>  
  </div>  
</template>  

<script>  
import ChildComponent from "./components/ChildComponent.vue";  
import About from "./components/About.vue";  
import Home from "./components/Home";  

export default {  
  name: "App",  
  data() {  
    return {  
      currentComponent: "Home"  
    }  
  },  
  components: {  
    ChildComponent,  
    About,  
    Home  
  }  
};  
</script>  
技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
駆け出しエンジニアからエキスパートまで全ての方々のアウトプットを歓迎しております!
or 外部アカウントで 登録 / ログイン する
クランチについてもっと詳しく

この記事が掲載されているブログ

@popy1017の技術ブログ

よく一緒に読まれる記事

0件のコメント

ブログ開設 or ログイン してコメントを送ってみよう