第14回 Vue.js スロットコンテンツ

差し込む プログラミング

こんにちは、コンスキです。

今回は、「スロットコンテンツ」というものについて説明します。

スロットコンテンツとは

スロットコンテンツとは、コンポーネントの中でも、コンポーネントを使うときになってから変更する(差し替える)ことができる部分のことです。

スロットコンテンツを設定しておくことで、コンポーネントを作成したあとからでも、用途に合わせて柔軟に部品を変更することができます。

例えば、内容がほんの少しだけしか異ならないコンポーネントを作るときに役に立ちます。ネットショピングのサイトを想像してみて下さい。

各商品を売るページでは、商品の写真、名前、説明などは商品ごとに異なるものの、逆にどの商品ページにも写真、名前、説明があり構成が共通しています。

いちいちコンポーネントのコードをコピーして異なる部分だけを変更してから使う、という作業は少し面倒です。

それに、そのような一度しか使わないであろうコンポーネントを作成するというのは、コードの変更に対する手間に対してそこまで利益が多くないように思えます。

そこで、使うときに変更できるようにしておく部分のことをスロットコンテンツといいます。

もちろん、変更できるようにしておくだけで、やっぱり変更しないで使おうという、こともできるので迚も便利なものです。

スロットコンテンツの作り方

スロットコンテンツには使い方に合わせた3種類のものがあります。

名前無しスロットコンテンツ

変更するかもしれない部分が、コンポーネントの中に一箇所しかない場合にこの名前無しスロットコンテンツを使います。

スロットコンテンツを作るには、コンポーネント作成時にあとから変更するかもしれない部分をslot要素というもので囲みます。

基本的な書き方は次のようになります。

HTML側↓

<div id="app">
  <コンポーネント名>コンポーネントのslot要素で囲んだ部分に入れたいもの</コンポーネント名>
</div>

Javascript側↓

Vue.conponent("コンポーネント名", {
  template: '
    <要素名>コンポーネントの内容<slot>ここにあるものがあとから変更できます</slot>コンポーネントの内容</要素名>
  '
})

ブラウザに実際に表示される画面のHTMLは次のように変わっています。

<div id="app">
  <要素名>コンポーネントslot要素の中に入れたいもの</要素名>
</div>

具体的な例を見てみましょう。名前が入ることを予定して、コンポーネント作成時に名前の部分をslot要素で囲んだ場合は次のようになります。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>スロットコンテンツ</title>
  <script src="https://unpkg.com/vue"></script>
</head>
<body>
  <div id="app">
    <test-component>コンスキ</test-component>
  </div>  
  <script>
    Vue.component("testComponent", {
      template: `
        <div>                                          //テンプレートは必ずしもdiv要素で囲む必要はありませんが                                   
          <p>私の名前は<slot>名前</slot>です。</p>      //一番外の要素がすべての要素を囲んでいいる必要があります
        </div>
      `
    })
    var vm = new Vue({
      el: "#app"
    })
  </script>
</body>
</html>

ブラウザに表示すると次のようになります。

コンポーネント作成時の「私の名前は<slot>名前</slot>です。」のslot要素に囲まれている部分が、

コンポーネント使用時の<test-component></test-component>の間に書いた「コンスキ」に置き換わっています。

名前付きスロットコンテンツ

名前無しスロットコンテンツを使ったのは、あとから変更するかもしれない部分が1つしかない場合でした。

一方で名前無しスロットコンテンツを使う必要があるのは、コンポーネントの後で変更するかもしれない部分が2つ以上ある場合です。

HTML側↓

<div id="app">
  <コンポーネント名>
    <template v-slot:要素1にあるスロットの名前>要素1のスロットコンテンツに差し込みたい内容</template>
    <template v-slot:要素2にあるスロットの名前>要素2のスロットコンテンツに差し込みたい内容</template>
  </コンポーネント名>
</div>

名前付きスロットコンテンツの基本的な書き方は次のようになります。template要素はそのまま「<template></template>」と書いて下さい。この部分に自分で作ったコンポーネントの名前を書かないように注意して下さい。

Javascript側↓

Vue.component("testComponent", {
  template: `
    <div>
      <要素名1>要素の内容<slot name="スロットの名前1">ここをあとから変更できます。</slot>要素の内容</要素名1>
      <要素名2>要素の内容<slot name="スロットの名前2">ここをあとから変更できます。</slot>要素の内容</要素名2>
    </div>
  `
  })
var vm = new Vue({
  el: "#app"
})

具体的例として、名前と年齢の2つを後で変更できるようにしたコンポーネントは、次のコードで作ることができます。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>スロットコンテンツ</title>
  <script src="https://unpkg.com/vue"></script>
</head>
<body>
  <div id="app">
    <test-component>
      <template v-slot:name>コンスキ</template>
      <template v-slot:age>19</template>
    </test-component>
  </div>  
  <script>
    Vue.component("testComponent", {
      template: `
        <div>
          <p>私の名前は<slot name="name">名前</slot>です。</p>
          <p>私の年齢は<slot name="age">年齢</slot>歳です。</p>
        </div>
      `
    })
    var vm = new Vue({
      el: "#app"
    })
  </script>
</body>
</html>

上のコードで「test-component」というコンポーネントを作ったときに、2つのslot要素を作りました。1つ目はname属性が「name」のslot要素で、2つ目はname属性が「age」のslot要素です。

コンポーネントを使う際は、1つ目のslot要素の中身を「コンスキ」で置き換えたくて、2つ目のslot要素の中身を「19」にかえたかったため次のようにHTMLに書きました。

ちなみに、名前を付けなかったスロットコンテンツには、自動的にdefaultという名前が付けられます。次のようなコードでも、名前無しコンテンツの中身を入れ替えることができます。

HTML側↓

<div id="app">
  <コンポーネント名>
    <template v-slot:default>スロットコンテンツに差し込みたい内容</template>
  </コンポーネント名>
</div>

Javascript側↓

Vue.component("コンポーネントの名前", {
      template: `
        <div>

          //↓のスロットコンテンツにはを付けていませんが自動的に name="default" というが書かれています。>
          <要素名>要素の内容<slot>ここにあとから変更したいものを書きます</slot>要素の内容</要素名>

        </div>
})

スコープ付きスロットコンテンツ

どんなときに使うのか

基本的には、

コンポーネントの使用時に差し込みたいものが子コンポーネントのデータだったとき

スコープ付きスロットコンテンツを使います。

具体的にはどんなときか説明します。次のようなコンポーネントがあったと考えて下さい。

Vue.component("chlidComponent", {
  template: `
    <div>
      <p>私の名前は<slot name="name">名前</slot>です。</p>
      <p>私の年齢は<slot name="age">年齢</slot>歳です。</p>
    </div>
  `,
  data: fucntion () {
    return {
     childName: "コンスキ",
     chileAge: 19
  }
})

このコンポーネントは、データプロパティに「childName」と「childAge」という2つの値を持っています。

では、個のコンポーネントを使うときに、親コンポーネントから、この2つの値を差し込もうと次のようなコードを書いた場合、どうなるでしょうか。

<div id="app">
  <child-component>
    <template v-slot:name>{{ childName }}</template>
    <template v-slot:age>{{ childAge }}</template>
  </child-component>
</div>

実は、これだと親コンポーネントから子コンポーネントのデータを使おうとしていることになります。

親コンポーネントと子コンポーネント間でのデータ受け渡しの説明時にも解説しましたが、親コンポーネントで「{{}}」の中へ、単純に子コンポーネントのデータのキーを書くだけでは、親コンポーネントで、子コンポーネントのデータを使うことはできません。

理由は、親コンポーネントのデータを呼び出すことができる範囲(スコープ)と子コンポーネントのデータを呼び出すことができる範囲が違うためでした。

そこで、スコープ付きスロットコンテンツでは、親コンポーネントに子コンポーネントのデータのスコープを渡してから、スロットコンテンツを使います。

「子コンポーネントのスコープを親コンポーネントへ渡す」という言葉の意味は、「子コンポーネントのデータを親コンポーネントの中でも使えるようにする」ということだと考えて下さい。

スコープ付きスロットコンテンツの使い方

基本的な書き方は次のようになります。

HTML側↓

<div id="app">
  <child-component>
    <template v-slot:default="子のデータのスコープ名">{{ 子のデータのスコープ名.このデータのキー }}</template>

  </child-component>
</div>

Javascript側↓

Vue.component("chlidComponent", {
  template: `
    <div>
      <要素名>要素の内容<slot v-bind:親で子のデータを使うときのキー"スコープを渡したい子のデータのキー">ここにあとから変更したいものを書きます</slot>要素の内容</要素名>
    </div>
  `,
  data: fucntion () {
    return {
     キー: "親に渡したい子のデータ"
  }
})
var vm =new Vue({
  el: "#app"
})

同じ色になっている部分には同じものが入ります。

書き方が複雑になっていて分かりづらいので、これも具体例を見てみます。

Vue.component("chlidComponent", {
  template: `
    <div>
      <p>私の名前は<slot name="name">名前</slot>です。</p>
      <p>私の年齢は<slot name="age">年齢</slot>歳です。</p>
    </div>
  `,
  data: fucntion () {
    return {
     childName: "コンスキ",
     chileAge: 19
  }
})

先程、こちらの「childComponent」のデータを、子コンポーネントのデータのスコープを親コンポーネントに渡さずに使おうとしていました。

今度は、しっかりスコープを渡して「childComponent」のデータを使ってみます。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>スロットコンテンツ</title>
  <script src="https://unpkg.com/vue"></script>
</head>
<body>
  <div id="app">
    <child-component>
      <template v-slot:name="childScope">{{ childScope.childName }}</template>
      <template v-slot:age="childScope">{{ childScope.childAge }}</template>
    </child-component>
  </div>
  <script>
    Vue.component("childComponent", {
      template: `
        <div>
          <p>私の名前は<slot name="name" v-bind:childName="childName">名前</slot>です。</p>
          <p>私の年齢は<slot name="age" v-bind:childAge="childAge">年齢</slot>歳です。</p>
        </div>
      `,
      data: function () {
        return {
          childName: "コンスキ",
          childAge: 19
        }
      }
    })
    var vm = new Vue({
      el: "#app"
    })
  </script>
</body>
</html>

これをブラウザに表示すると次のようになります。

これで今回のスロットコンテツに関する説明を終わりにします。読んでくれてありがとうございました。

次回からは、Vue Routerのというライブラリの説明に入っていきます。Vue Routerを使うとシングルーページアプリケーションというものを作れます。

シングルページアプリケーションは、ブラウザのページの移り変わりが行われないようアプリケーションです。

ページの移り変わりがない分、アプリケーションの動作を軽くすることができます。

まとめ

  • 子コンポーネントの中でスロットコンテンツを作ると、親コンポーネントで使用する際に柔軟にスロットコンテンツの中身を変えることができる
  • スロットコンテンツには3種類あり、使い分ける必要がある

コメント

タイトルとURLをコピーしました