Vue.js のカスタムディレクティブを使う

最終更新日
2017.10.31

カスタムディレクティブのお勉強します。

前回の描画関数に続いて今まであまり触っていないカスタムディレクティブを使ってみます。

カスタムディレクティブの使い所

フォームの disable などを直接操作したり、他のライブラリとの連携で JavaScript プロパティやメソッドに直接アクセスしたい場合にシンプルに書けるみたいです。でもカスタムディレクティブで出来ることはコンポーネントの細分化やウォッチャーでも大体出来るので使い分けは曖昧なところです。

カスタムディレクティブの書き方

Vue.directive('name', { ... }) で登録するとグローバルに、コンポーネントの directives オプションでローカルで登録できます。

Vue.component('my-component', {
  directives: {
    example: {
      bind: function () { ... },
      update: function () { ... }
    }
  }
})

コンポーネントの bindinsertedupdatecomponentUpdatedunbind のイベントにフック出来ます。省略して関数を渡すと bindupdate に同じ処理が登録されます。

ちなみに this は使えないので代わりに、3番目の引数の vnode.context で呼び出しているコンポーネントを参照できます。

Vue.component('my-component', {
  directives: {
    example: function (el, binding, vnode) {
      vnode.context.$emit('event')
    }
  }
})

フォームの属性操作に便利

フォームアイテムの属性や audiovideo などの属性を操作したい時に便利です。例えば入力内容によってボタンの disable の切り替えにカスタムディレクティブを使ってみます。

<p><input v-model="data1"> <button v-disable="data1.length>5">ボタン</button></p>
<p><input v-model="data2"> <button v-disable="data2.length>5">ボタン</button></p>
new Vue({
  el: '#app',
  data: function () {
    return {
      data1: 'サンプル',
      data2: 'サンプルデータ',
    }
  },
  directives: {
    disable: function (el, binding) {
      el.disabled = binding.value
    }
  }
})

入力の長さが5文字以下の時だけボタンを有効にします。

エディタのプレビューを作る

最近良く使っているのが Shadow DOM を使ったプレビューエリア。以前は iframe を使ってましたが便利です。社内ツール開発なので出来ることなんですけどまだサポートブラウザが少ないので注意。

Vue.directive('preview', {
  bind(el, binding, vnode) {
    el.attachShadow({ mode: 'open' })
    el.shadowRoot.innerHTML = binding.value
  },
  update(el, binding, vnode) {
    if (vnode.elm.shadowRoot.innerHTML !== binding.value) {
      el.shadowRoot.innerHTML = binding.value;
    }
  }
})
new Vue({
  el: '#app',
  data: {
    content: '<b>test</b>',
  }
})
<div id="app">
  <h4>エディタ</h4>
  <textarea v-model="content"></textarea>
  <h4>プレビュー</h4>
  <div v-preview="content" class="preview"></div>
  <p>タグの閉じ忘れがあっても外側に影響しない。</p>
</div>

プレビュー用のディレクティブが複数使用されている場合、更新前の状態と比較することで無駄な再描画をしないようにできる。

おわりに

どんな時に使えるか少し分かってきたのでこれから色々作っていく時に「これはカスタムディレクティブを使ったら出来そう」ってなる事が出てくるかも。使いこなすととても便利そうです。そのうち何か簡単なプラグインも作ってみたいですね(•ө•)ノ

次回は再び Vuex のお勉強で、API を使ってもう少し実践的な使い方をしてみたいと思います。