【Vue.js】ざっくり紹介、Vueプラグインの書き方

おひさしぶりです、橋本です。

みなさんVue書いてますか!?
自分はここ数年ひたすらVueで開発しています。
いやーいいですよね、Vue。
なんか知らんけど良いんですよね。手に馴染むというか。
大好きVue。

ところで、Vue のプラグインってみなさん使ったことありますか?
vue-router や vuex など何かしらのプラグインを使ったことがある人がほとんどだと思います。

では、プラグインを「作った」ことのある人、どれぐらいいますか?
なんとなく難しそうというイメージで作ったことないって人、結構いるんじゃないでしょうか??

実は Vue のプラグインを作るのってすごく簡単なんです。
今日はその作成方法をざっくりご紹介したいと思います。

基本的な作り方

Vue のプラグインを作成する方法なんですが、

「install メソッドを持つオブジェクトを定義する」

ただこれだけなんです。
定義したプラグインはご存知のとおり、Vue.use メソッドで使用します。

Vue.use メソッドを使ってプラグインを使用すると、プラグインのinstall メソッドが呼ばれるって感じです。
install メソッドの第一引数は Vue コンストラクタ、第二引数はオプションのオブジェクトになります。

一番簡単なプラグインの例はこんな感じ。

const MyPlugin = {
  install(Vue, options) {
    console.log(`${options.hello}${options.world}!`)
  }
}
Vue.use(MyPlugin, { hello: 'こんにちは', world: '世界' }) // こんにちは世界!

プラグインの install メソッドの中では、主に以下の4つの項目を設定していくことになります。

  1. グローバルメソッド・プロパティ
  2. directive、filter、component などのグローバルアセット
  3. クローバルミックスイン
  4. Vue のインスタンスメソッド・プロパティ

今回はひとつずつ使用例を見て行きたいと思います。

1. グローバルメソッド・プロパティ

Vue コンストラクタ自身に独自のメソッドやプロパティを設定することができます。

const MyPlugin = {
  install(Vue, options) {
    Vue.$_myProperty = options.foo
    Vue.$_myMethod = () => {
      console.log(options.bar)
    }
  }
}
Vue.use(MyPlugin, { foo: 'フー!', bar: 'バア!' })
console.log(Vue.$_myProperty) // 'フー!'
Vue.$_myMethod() // 'バア!'

便利といえば便利ですが、インスタンスメソッド・プロパティに比べるとあまり使わないかなーという感じです。

次。

2. directive、filter、component などのグローバルアセット

プラグインを通じてグローバルレベルの directive や filter 、component などを定義しておくことで、各コンポーネントで共通して利用することができます。
指定したタグにフォーカスを当てる directive や、moment 使って date フォーマットする filter、様々なところで汎用的に用いる component などを定義しておくと便利ですよね。

import moment from 'moment'
import BaseLabel from '@/components/BaseLabel.vue'
const MyPlugin = {
  install(Vue) {
    // 指定したタグにフォーカスを当てるdirectiveを書いてみたり、
    Vue.directive('focus', {
      inserted(el) {
        el.focus()
      }
    })
    // momentでdateをフォーマットするfilterを書いてみたり、
    Vue.filter('formatDate', (date, format = 'YYYY-MM-DD') => {
      return moment(date).format(format)
    })
    // importしたコンポーネントを登録したり、
    Vue.component('BaseLabel', BaseLabel)
    // 直接コンポーネントを定義したり
    Vue.component('BaseButton', {
      name: 'BaseButton',
      render(h) {
        return h('button', { class: 'base-button' }, this.$slots.default)
      }
    })
  }
}
Vue.use(MyPlugin)
<template>
  <base-label>はろー</base-label>
  <base-button>ぽちっとな</base-button>
  <input v-focus />
  <span>{{ Date.now() | formatDate('YYYY年MM月DD日') }}</span>
</template>

これは便利。

次。

3. グローバルミックスイン

おなじみの mixin ですが、グローバルに mixin を適用するとすべての Vue インスタンスで使用することができます。

ただし、全ての Vue インスタンスに影響が出るので、使用する場合は注意が必要です。
data、methods、computed などは上書きする形でマージされるのですが、ライフサイクルフック(created, beforeMount, mounted など)は注意が必要です。
ライフサイクルフックは、mixin に定義したものもコンポーネントで定義したものも全て実行されてしまいます。
なので、ほんとに各コンポーネントで実行されても問題の無い処理のみ書くようにしたほうが良さそうですね。

const MyPlugin = {
  install(Vue, options) {
    Vue.mixin({
      created() {
        console.log('1本でもにんじん')
      },
      data() {
        return {
          firstName: 'ひろ',
          lastName: 'つ○だ'
        }
      },
      computed: {
        fullName() {
          return `${this.lastName} ☆ ${this.firstName}`
        }
      }
    })
  }
}
Vue.use(MyPlugin)
export default {
  created() {
    console.log('2足でもサンダル')
  },
  data() {
    return {
      firstName: 'ジ○ス',
      lastName: 'ゴー'
    }
  }
}

ご利用は計画的に。

次。

4. Vue のインスタンスメソッド・プロパティ

Vue.prototype にプロパティやメソッドを追加することで、全ての Vue インスタンスで利用可能です。

const MyPlugin = {
  install(Vue) {
    Vue.prototype.$_myProperty = 'チョコレート'
    Vue.prototype.$_myMethod = () => {
      console.log('食べたい!')
    }
  }
}
Vue.use(MyPlugin)
export default {
  mounted() {
    console.log(this.$_myProperty)
    console.log(this.$_myMethod())
  }
}

mixin で data とか method 定義するのと同じやん!って思うかもしれませんが、インスタンスメソッド・プロパティとして定義すると、コンポーネントの初期化前(beforeCreate ライフサイクル時)でも使用することができます。

const MyPlugin = {
  install(Vue) {
    Vue.prototype.$_myProperty = 'チョコレート'
    Vue.prototype.$_myMethod = () => {
      console.log('食べたい!')
    }
    Vue.mixin({
      data() {
        return {
          myProperty: 'バナナ'
        }
      },
      methods: {
        myMethod() {
          console.log('食べたくない!')
        }
      }
    })
  }
}
Vue.use(MyPlugin)
export default {
  beforeCreate() {
    console.log(this.$_myProperty) // 'チョコレート'
    this.$_myMethod() // '食べたい'
    console.log(this.myProperty) // undefined
    this.myMethod() // Error
  },
  created() {
    console.log(this.$_myProperty) // 'チョコレート'
    this.$_myMethod() // '食べたい'
    console.log(this.myProperty) // 'バナナ'
    this.myMethod() // '食べたくない'
  }
}

自分はwindow リサイズイベントに合わせて値が変わるインスタンスプロパティを定義したりして使ってます。
これ便利。

const MyPlugin = {
  install(Vue) {
    const $_windowSize = Vue.observable({
      height: document.documentElement.clientHeight,
      width: document.documentElement.clientWidth
    })
    const handleWindowResize = () => {
      $_windowSize.height = document.documentElement.clientHeight
      $_windowSize.width = document.documentElement.clientWidth
    }
    window.addEventListener('resize', handleWindowResize)
    Vue.prototype.$_windowSize = $_windowSize
  }
}
Vue.use(MyPlugin)
export default {
  watch: {
    $_windowSize: {
      handler(newValue) {
        console.log(`height: ${newValue.height}, width: ${newValue.width}`)
      },
      deep: true
    }
  }
}

いかがでしたでしょうか??
思っていたよりも簡単じゃないですか??

みなさんもプラグインを使いこなして楽しいVue ライフをお過ごしくださいませ!

終わり!