第21回 Vue.js入門 ミックスイン

ミックスイン 未分類

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

今回は、ミックスというものについて説明します。

ミックスインとは

ミックスインとは、共通した機能やデータを複数のコンポーネントで使うための機能です。

共通したで機能やデータは、コンポーネントを作成するときに設定するdataプロパティやmethodsプロパティなどを指しています。

どんな場面で使うことができるのか具体例を使って説明します。

例えば、ボタンが押されたときにdataプロパティに設定したmessageというプロパティにある文字列をalertとして画面に表示させるコンポーネントを作った場合を考えて下さい。

ButtonAlert = {
  template: `
    <div>
      <button v-on:click="displayAlert">押してね</button>
    </div>
  `,
  data: function () {
    return {
      message: "ボタンが押されました。"
    }
  },
  methods: {
    displayAlert: function () {
      alert(this.message)
    }
  }
}

加えて同じように、ボタンが押されたらdataプロパティにあるmessageプロパティの文字列を表示される機能を持っているけれど、ボタンには違う文字が書かれていて、テキストエリアも持っているコンポーネントを作ります。

SubmitAlert = {
  template: `
    <form>  
      <textarea></textarea>
      <br>
      <button v-on:click="displayAlert">送信</button>
    </form>
  `,
  data: function () {
    return {
      message: "送信ボタンが押されました。"
    }
  },
  methods: {
    displayAlert: function () {
      alert(this.message)
    }
  }
}

以上の2つのコンポーネントを使った場合、次のようにブラウザに表示されます。

まず、上の「押してね」と書かれたボタンを押すと次のようなアラートが表示されます。

一方で、下の「送信」と書かれたボタンを押すと、次のようなアラートが表示されます。

この2つのコンポーネントとは、見た目は違っていても、「ボタンが押されたらdataプロパティのmessageプロパティの文字列のアラートを表示する」という機能は共通しています。

このように共通している機能を複数のコンポーネントが持っているときは、機能だけでまとめて何度も違うコンポーネントに使えるようにしたほうがコンポーネントを作る際に同じコードを書く手間が省けます。

また、後から共通している機能を変更する際には、まとめてあった機能だけを変更するだけで、その機能を使っているすべてのコンポーネントの機能を変えることができるというような利点もあります。

この例の場合は、methodsプロパティの「displayAlert」というメソッドはまとめておくことができます。

このような機能やデータをまとめたもの、またはまとめる機能をミックスインといいます。

ミックスインの使い方

ミックスインを使うときに、まずは機能(プロパティ)を次のようにまとめて書いておきます。

var ミックスインの名前 = {
  //ここに後で複数のコンポーネントで使いたいプロパティを書きます。
}

その後、次のようにミックスインを使いたいコンポーネント、またはVueインスタンスの中でmixinsプロパティを設定することでミックスインのプロパティを使うことができます。

var コンポーネント名 = {
  mixins: [ 使いたいミックスインの名前 ]
} 
var vm = new Vue({
  el: "#app",
  mixins: [ 使いたいミックスインの名前 ]
})

例として、「ボタンを押したらdataプロパティにあるmessageプロパティの文字列をアラートとして表示する」というmethodsプロパティをミックスインを作ることで1つにまとめてみます。

var Alertable = {
  methods: {
    displayAlert: function () {
      alert(this.message)
    }
  }
}

次に、「ButtonAlert」というコンポーネントと「SubmitAlert」という2つのコンポーネントのmixinsプロパティに、いま作った「Alertable」というミックスインを追加します。

var ButtonAlert = {
  mixins: [ Alertable ],
  template: `
    <div>
      <button v-on:click="displayAlert">押してね</button>
    </div>
  `,
  data: function () {
    return {
      message: "ボタンが押されました。"
    }
  }
}
var SubmitAlert = {
        mixins: [ Alertable ],
  template: `
    <form>  
      <textarea></textarea>
      <br>
      <button v-on:click="displayAlert">送信</button>
    </form>
  `,
  data: function () {
    return {
      message: "送信ボタンが押されました。"
    }
  }
}

これで、共通しているmethodsプロパティの部分を一度だけ書いただけで「ButtonAlert」と「SubmitAlert」のどちらにも同じmethodsプロパティが追加されました。

ブラウザに表示して、ボタンを押してみても、methodsプロパティをミックスインにまとめずに2回書いたときと同じように、アラートが表示されます。

ミックスインとしてまとめておくことができるのは、methodプロパティだけではなく、dataプロパティやcomputedプロパティなどの、コンポーネントに設定することができるプロパティです。

例えば、ミックスインとしてdataプロパティとcomputedプロパティをまとめた場合は次のようになります。

var Claculateable = {
  data: function () {
    return {
      price: 0,
      quantity: 0
    }
  },
  computed: {
    calcTotalAmount: function () {
      var totalAmount = this.price * this.price
      return totalAmount  
    }
  }
}

複数のミックスインを使う

ミックスインをコンポーネントに追加するときに、mixinsプロパティの配列に複数のミックスインの名前を設定することで、複数のミックスインを同時に追加することができます。

//ミックスインを複数作っておく
var Mixin1 = {
  //ここに複数のコンポーネントで共通して使うプロパティを書きます
}
var Mixin2 = {
  //ここに複数のコンポーネントで共通して使うプロパティを書きます
}
   ︙
var コンポーネント名 = {
  mixins: [ Mixin1, Mixin2, … ]
} 

例として、ミックスインを2つを作って、コンポーネントで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">
    <calc-component></calc-component>
  </div>
  <script>
    var Calculateable = {
      data: function () {
        return {
          price: 0,
          quantity: 0
        }
      },
      computed: {
        totalAmount: function () {
          var totalAmount = this.price * this.quantity
          return totalAmount  
        }
      }
    }
    var Displayable = {
      methods: {
        displayTotalAmount: function () {
         alert("合計金額は" + this.totalAmount + "円です")
        }
      }
    }
    var CalcComponent = {
      mixins: [ Calculateable, Displayable ],
      template : `
        <div>
          <p>1個あたりの値段(円)</p>
          <input type="text" v-model="price"></input>
          <p>個数</p>
          <input type="number" v-model="quantity"></input>
          <button v-on:click="displayTotalAmount">計算する</button>
        </div>
      `
    }
    const vm = new Vue({
      el: "#app",
      components: {
        "calc-component": CalcComponent
      }
    })
  </script>
</body>
</html>

上のコードをブラウザに表示します。

合計金額を計算するための「Calculateable」というミックスインと、合計金額をアラートとして表示する「Alertable」というミックスインが、「CalcComponent」というコンポーネントでどちらとも使えているのか確かめます。

正しい合計金額がアラートとして表示されたことから、「CalcComponent」というコンポーネントで2つのミックスインが両方とも使われている事がわかります。

ミックスインとコンポーネントに同じプロパティがあったとき

結論としては、ミックスインとコンポーネントに同じプロパティがあったときは、コンポーネント側のプロパティが優先されます。

このことについて、詳しく説明します。

ミックスインで機能を追加しようとしたときに、すでに同じプロパティをコンポーネントが持っている事があります。

上の例では、ミックスインのmethodプロパティとミックスが追加される側のコンポーネントのmethodプロパティのどちらにも「displayAlert」というメソッドがあります。

そのようなとき、ミックスイン側の「displayAlert」とコンポーネント側の「displayAlert」では、どちらのプロパティがミックスインが追加された後のコンポーネントのプロパティとなるでしょうか?

次のコードをブラウザに表示して確認してみます。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>ミックスイン</title>
  <script src="https://unpkg.com/vue"></script>
</head>
<body>
  <div id="app">
    <display-component></display-component>
  </div>
  <script>
    var Displayable = {
      methods: {
        displayAlert: function () {
         alert("ミックスインのメソッド")
        }
      }
    }
    var DisplayComponent = {
      mixins: [ Displayable ],
      template : `
        <div>
          <p>どちらのメソッドが使われる?↓</p>
          <button v-on:click="displayAlert">押してね</button>
        </div>
      `,
      methods: {
        displayAlert: function () {
         alert("コンポーネントのメソッド")
        }
      }
    }
    const vm = new Vue({
      el: "#app",
      components: {
        "display-component": DisplayComponent
      }
    })
  </script>
</body>
</html>

アラートに書かれていることから、ミックスインを追加した後のコンポーネントの「displayAlert」として使われたのは、コンポーネント側のメソッドであることがわかります。

追加するミックスインにも、追加されるコンポーネントにも同じキーのプロパティがあった場合には、すでに持っていたコンポーネント側のプロパティが優先されることに注意して下さい。

ライフサイクルフックもミックスインにまとめられる?

複数のコンポーネントで同じライフサイクルフックの関数を設定することがあります。

このようなとき、ライフサイクルフック関数もミックスインにまとめておいて、コンポーネントにミックスインとして追加することができます。

しかし、ここでも疑問が生まれます。

これまで1つのライフサイクルフックには、1つの関数しか設定しなかったと思いますが、コンポーネントにライフサイクルフック関数がすでに設定されている状態で、同じライフサイクルフックの関数を設定しているミックスインを追加した場合どうなるのでしょうか?

それを確認するために、次のコードをブラウザに表示してGoogle DebToolsのConsoleを見てみます。

コンソールに表示されている内容から、2つの関数が実行されているのがわかります。

そして、表示されている順番からミックスインのcreatedフック関数が処理されて、その次のコンポーネントのフック関数が処理されていることがわかりますね。

createdフック関数に2つの関数が設定されている状態になったのではなく、もしかすると一つの関数の中に2つの関数の処理がまとめられたのかもしれません。

(すみませんm(_ _)m詳しくはわかりません)

はっきりしていることは、ミックスインが使われるコンポーネントにすでに同じライフサイクルフックの関数があったときは、どちらのライフサイクルフックの関数も実行されるということです。

まとめ

今回わかったこと

  • 複数のコンポーネントで共通しているプロパティを設定する場合、1つのミックスインにまとめておくことができる
  • 1つのコンポーネントには、複数のミックスインを追加することができる
  • ミックスインが追加されるコンポーネントにすでに同じキーのプロパティがあった場合、コンポーネントのプロパティが優先される
  • ライフサイクルフック関数もミックスインの中にまとめておくことができる

コメント

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