2017/07/06

Vue.jsのMixin機能でViewModelを共通化する

photo by César Astudillo

Vue.jsを開発しているとおのずとViewModel(computedやmethodsなど)が肥大化してしまう。

Vuexを使ってActionsやMutationsに処理を掃き出すこともできるが、小規模アプリケーションだと逆に面倒だ。そもそもVuexは状態管理ライブラリなので、処理の共通化を目的に導入することもおかしな気もする。

jsファイルを作成、importして使うことも考えられるが、@click="method" みたいに直接メソッド名が指定できないので結局ViewModelが肥大化してしまう。

何か良い方法はないかとドキュメントを読んでいたところ、Mixin(ミックスイン)を使うことで解消できるらしい。

ということで、Mixin機能を使ってViewModelをスリムにしようと思う。

Mixinについて


ミックスイン (mixin) は、Vue コンポーネントに再利用可能で柔軟性のある機能を持たせるための方法です。ミックスインオブジェクトは任意のコンポーネントオプションを含むことができます。コンポーネントがミックスインを使用するとき、ミックスインの全てのオプションはコンポーネント自身のオプションに”混ぜられ”ます。
ミックスイン - Vue.js

ViewModel部分を別に定義しておいて、それをMixinすることでVueコンポーネントから利用することができる。クラスを継承したときに派生クラスから基底クラスのメソッドを参照できるのに似ている。

次に、実際に例をあげる。



MixinでViewModelを共通化する


// mixinA.js
export default {
  created () {
    console.log('loaded mixinA')
  },
  methods {
    methodA () {
      console.log('methodA')
    },
    methodAwithParam (param) {
      console.log(`self: ${param}`)
    }
  }
}
// mixinB.js
export default {
  created () {
    console.log('loaded mixinB')
  },
  methods {
    methodB () {
      console.log('methodB')
    }
  }
}
<!-- component.vue: 単一コンポーネント -->
<template>
  <div>
    <label>data</label><input type="text" v-model="data">
    <button @click="methodA">A</button>
    <button @click="methodB">B</button>
    <button @click="selfMethod">self</button>
  </div>
</template>

<script>
import mixinA from '@/mixinA'
import mixinB from '@/mixinB'

export default {
  mixins: [mixinA, mixinB],
  data () {
    return {
      data: ''
    }
  },
  created () {
    console.log('loaded main')
  },
  methods: {
    selfMethod () {
      this.methodAwithParam(this.data)
    }
  }
}
</script>

上記コードでは、mixinA.jsとmixinB.jsの2つのミックスインオブジェクトを定義し、双方を読み込んでいる。

これを実行すると、、、
// ロード時
loaded mixinA
loaded mixinB
loaded main

// ボタンAをクリック
methodA

// ボタンBをクリック
methodB

// ボタンselfをクリック
self: `hoge`

興味深い点は、createdの処理がコンポーネント内、mixinA.js、mixinB.jsのすべてに実装されており、それが順番に実行される点だ。
Mixinとコンポーネントのオプションが重複する場合、Mixin→コンポーネントの順に呼び出される。今回の例でいうと、mixinA#created → mixinB#created → component#created が呼び出されている。

ただし同名のオブジェクト(たとえばmethodsに実装した同名のメソッドなど)の場合は、コンポーネントに実装されているものが優先される


追記: 2017/12/12 16:00
Mixinで使うプロパティには$_プレフィックスをつけるようにすべきだそうです。(参照: プライベートなプロパティ名-スタイルガイド
理由はコンポーネントのプロパティ名との衝突を避けるため。





[Tips] import A from '@/A'


Mixinのサンプルコードで何気なく「import mixinA from '@/mixinA'」と書いている。

vue-cliでスキャフォールディングした場合、「@」を使うことで「./src」のルートディレクトリを指せるので、「../../mixinA」ではなく「@/mixinA」のように指定できる。

「@」でルートディレクトリを指すのはECMAScriptの仕様ではなくWebpackの機能なので注意。( 参照: vuejs-templates/webpack - webpack.base.conf.js )



以上

written by @bc_rikko

0 件のコメント :

コメントを投稿