vue.jsのカスタムディレクティブを使ってdata属性を付与する

## この記事の内容

Webサービス開発でユーザーの行動データを集計するのにGoogle Analyticsを使っています
リンクを踏んだりとかボタンをクリックしたりみたいなものは簡単にかけますが、それをさらに細分化したくなるとdata属性を埋め込むようになると思います

ただ、その時に直接data属性を追加してしまうと、変更箇所や新しい実装のときにdata属性を付け忘れていないか?data属性の記述はtypoしていないか?などを常に意識する必要がでてきます

Vuejsのディレクティブを活用して、上記の問題を軽減してみようという話です

## ステップ1: data属性の定義をコンポーネントに含める

```Button.vue
<template>
  <button data-category="button" data-action="click">
    Button
  </button>
</template>
```
```index.vue
<template>
  <Button />
</template>
```
```出力.html
<button data-category="button" data-action="click">
  Button
</button>
```

### なにをしたか
Buttonという小さいコンポーネント定義した
data属性の定義をコンポーネントに持たせた

### どうなったか
コンポーネントにイベントの情報を持たせたので実装のときにdata属性のことを意識しなくてよい

## ステップ2: vueのディレクティブを使用して役割を切り離す
ステップ1の実装で困る状況は、「そのコンポーネント以外でも同じイベント取りたい!」ってなったときにその部分だけいままで通り直接実装することになってしまいます
そこでVuejsの[カスタムディレクティブ](https://jp.vuejs.org/v2/guide/custom-directive.html)を使うことで特定のdata属性を追加するという処理をButtonから切り離します


```data.js
// クリックイベント用のディレクティブ
// クリックイベントを計測したい場合は、このディレクティブを追加してください
Vue.directive('data-action-click', { // v-data-action-clickというディレクティブが追加される
  bind: function (el) { // このelはディレクティブを追加したDOM
    el.setAttribute('data-category', 'button') // data-category="button" というdata属性を追加
    el.setAttribute('data-action', 'click')    // data-action="click" というdata属性を追加
  }
})
```
```Button.vue
<template>
  <button class="btn" v-data-action-click="button"> <!-- この指定だけで2つのdata属性を追加できる -->
    Button
  </button>
</template>
```
```index.vue
<template>
  <div id="app">
    <Button />
    <div class="btn" v-data-action-click> <!-- Button以外でもディレクティブを追加すれば同様に使える -->
      Div
    </div>
  </div>
</template>
```
```出力.html
<button data-category="button" data-action="click">
  Button
</button>
<div class="btn" data-category="button" data-action="click">
  Div
</div>
```

### なにをしたか
v-data-action-clickというディレクティブを追加した

### どうなったか
Button以外でも簡単にdata属性を追加できるようになった
data属性を複数追加する必要があるときも、ディレクティブ1つを追加するだけで良い
なので、追加でdata属性を追加するときもディレクティブの定義を修正するだけで作業が終わる

### ステップ3: ディレクティブのbindingを使って動的な値も渡せるようにする
ステップ2の実装で困る状況は、「data-action="search"みたいなのを追加したいけどいちいちディレクティブを追加しないとなの?面倒じゃね??」

はい、面倒です、なので[ディレクティブフック引数](https://jp.vuejs.org/v2/guide/custom-directive.html#%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%86%E3%82%A3%E3%83%96%E3%83%95%E3%83%83%E3%82%AF%E5%BC%95%E6%95%B0)を使いましょう
結構カスタムできます、以下に簡単な実装例を書きます

```data.js
// クリックイベント用のディレクティブ
// クリックイベントを計測したい場合は、このディレクティブを追加してください
// v-data-action-click="ここに入れた値がexpressionになる"
Vue.directive('data-action-click', {
  bind: function (el, binding) {
    el.setAttribute('data-category', binding.expression)
    el.setAttribute('data-action', 'click')
  }
})
```
```Button.vue
<template>
  <button class="btn" v-data-action-click="'button'">
    Button
  </button>
</template>
```
```Main.vue
<template>
  <div id="app">
    <Button />
    <div class="btn" v-data-action-click="'div'">
      Div
    </div>
  </div>
</template>
```
```出力.html
<button data-category="button" data-action="click"> <!-- categoryがbuttonになる -->
  Button
</button>
<div class="btn" data-category="div" data-action="click"> <!-- categoryがdivになる -->
  Div
</div>
```

### なにをしたか
ディレクティブのexpressionを受け取ってdata-categoryに設定されるようにした

### どうなったか
動的な値を渡せるので、基本形だけディレクティブで作成してしまえばあとは追加で実装する頻度はステップ2よりは少なくなりそう


## さいごに
data属性をべた書きするよりは色々と便利だったりメンテナンスコスト低いと思っているのでこんな感じでやってみようかなと思っている最中です
他にやり方やアドバイスなどあればコメントとか編集リクエストとかください

### 参考
デモ: [sample-vue-custom-directive](https://sinshutu.github.io/sample-vue-custom-directive/index.html)
リポジトリ: [sinshutu/sample-vue-custom-directive](https://github.com/sinshutu/sample-vue-custom-directive/tree/master)