Vue.jsを更に学ぶ(6日目)

#カスタムディレクティブ

```Home.vue
<template>
  <p v-border>Home</p>  
</template>
```

まずは、v-以下に任意の名前を付ける。

```main.js
//一つ目の引数はカスタムディレクティブの名前
//二つ目はオブジェクトを取る
Vue.directive("border", {
  bind() {},
  inserted() {},
  update() {},
  componentUpdated() {},
  unbind() {},
})
```

その後、main.jsで5つのフック関数を持ったvueインスタンスを作成。


```main.js
Vue.directive("border", {
  bind(el, binding, vnode) {
    //ディレクティブが初めて対象の要素に紐づいた時
  },
  inserted(el, binding, vnode) {
    //親Nodeに挿入された時
  },
  update(el, binding, vnode, oldVnode) {
    //コンポーネントの情報が少しでも変わった時
    //子コンポーネントが更新される前
  },
  componentUpdated(el, binding, vnode, oldVnode) {
    //コンポーネントの情報が少しでも変わった時
    //子コンポーネントが更新された後
  },
  unbind(el, binding, vnode) {
    //ディレクティブが紐づいている要素から取り除かれた時
  },
})
```

各フック関数では引数を取ることができる。
updateとcomponentUpdatedだけは4つ目の引数を取ることができる。

ただ、基本的にはbindとupdateの2つをメインで使うことが多い。

##省略記法

```main.js
Vue.directive("border", function (el, binding) {
  
})
```

上位の省略記法では、bindとupdateのフック関数として適用される。

##elを使ってcssをつけてみよう

```main.js
Vue.directive("border", function (el) {
  el.style.border = "solid black 2px";
})
```

このように書くと、マウンティングされた要素の周りに線が表示される。
これは直接domにアクセスしてるらしい。


##binding.valueを使ってデータを渡す

```Home.vue
<template>
  <p v-border="'5px'">Home</p>  
</template>
```

枠線の太さを5pxにしたいとする。

まずは、v-border="'5px'"とする。
気をつけなければいけないのは、
""の中は本来js式が入るので、文字列を入れたい時は' 'で囲んであげる必要がある。

次に

```main.js
Vue.directive("border", function (el, binding) {
  el.style.border = "solid black 2px";
  el.style.borderWidth = binding.value;
})
```

注目すべきは

```js
el.style.borderWidth = binding.value;
```

binding.valueでHome.vueで指定した5pxを受け取っている。

こうすることで、枠線の太さを5pxに変えることができた。

##binding.valueで受け取るデータをオブジェクトにする

```Home.vue
<template>
  <p v-border="{widht: '5px', color: 'red'}">Home</p>  
</template>
```
渡したいデータをオブジェクトで指定する

```main.js
Vue.directive("border", function (el, binding) {
  el.style.border = "solid black 2px";
  el.style.borderWidth = binding.value.width
  el.style.borderColor = binding.value.color
})
```

このように、binding.value.widthのようにすることで、オブジェクトの特定の値を持ってくることができる。

##カスタムディレクティブで引数を扱う

```Home.vue
<template>
  <p v-border:dotted="{widht: '5px', color: 'red'}">Home</p>  
</template>
```

引数をつけるには、

v-border:引数名　とする。


```main.js
Vue.directive("border", function (el, binding) {
  el.style.border = "solid black 2px";
  el.style.borderWidth = binding.value.width
  el.style.borderColor = binding.value.color
  el.style.borderStyle = binding.arg
})
```
注目すべきは

```js
el.style.borderStyle = binding.arg
```

binding.argで引数名を取得することができる。

これで、枠線が点線になる。


##修飾子をカスタムディレクティブに使う

```Home.vue
<template>
  <p v-border:solid.round.shadow="{widht: '5px', color: 'red'}">Home</p>  
</template>
```

.round.shadowのようにいくつもつなげることができる。

```main.js
Vue.directive("border", function (el, binding) {
  el.style.border = "solid black 2px";
  el.style.borderWidth = binding.value.width
  el.style.borderColor = binding.value.color
  el.style.borderStyle = binding.arg
  //roundという修飾子があればtrueを返す
  if (binding.modifiers.round) {
    el.style.borderRadius = "0.5rem"
  }
  if (binding.modifiers.shadow) {
    el.style.boxShadow = "0.2px 5px"
  }
})
```

注目すべきは

```js
if (binding.modifiers.round) {
    el.style.borderRadius = "0.5rem"
}
if (binding.modifiers.shadow) {
  el.style.boxShadow = "0.2px 5px"
}
```

binding.modifiers.修飾子名

とすることで、もしその修飾子があればtrueを返してくれる。


##ローカルにカスタムディレクティブを登録

先ほどmain.jsに書いていた処理をHome.vueで書けば良い

```Home.vue
<template>
  <p v-border:solid.round.shadow="{widht: '5px', color: 'red'}">Home</p>  
</template>

<script>
export default {
  directives: {
    //border: function() {}はES5
    //以下はborder()というES6の書き方
    border(el, binding) {
      el.style.border = "solid black 2px";
      el.style.borderWidth = binding.value.width
      el.style.borderColor = binding.value.color
      el.style.borderStyle = binding.arg
      //roundという修飾子があればtrueを返す
      if (binding.modifiers.round) {
        el.style.borderRadius = "0.5rem"
      }
      if (binding.modifiers.shadow) {
        el.style.boxShadow = "0.2px 5px"
      }
    }
  }
}
</script>
```

scriptタグ内に、directives:というプロパティを用意して、
そこにカスタムディレクティブを定義していくスタイル。


注意点としては、カスタムディレクティブ内ではthisを使うことができない。
thisを使えるのはmethodsやcomputedなど。

#フィルター

フィルターとはテキストをフォーマット化するツール。

まずは、main.jsにフィルターを定義する

```main.js
Vue.filter("upperCase", function(value) {
  return value.toUpperCase()
})
```

第一引数には任意のフィルター名、第二引数に関数を取る。

次に、フィルターを適応させたいプロパティにパイプ記号を使って書く。

```Home.vue
<template>
  <div>
    <p v-border:solid.round.shadow="{widht: '5px', color: 'red'}">Home</p>
    <h2>{{ title | upperCase }}</h2>
    <p>{{ subTitle | upperCase }}</p>
  </div>
</template>
```

こうすることで、titleというプロパティがuppaerCaseというフィルターを通じて表示されることとなる。


##ローカルにフィルターを定義する

```HOme.vue
<script>
export default {
  data(){
    return {
      title: "Hello!!",
      subTitle: "good morning!"
    }
  },
  filters: {
    lowerCase(value) {
      return value.toLowerCase()
    }
  },
  
  directives: {
    //border: function() {}はES5
    //以下はborder()というES6の書き方
    border(el, binding) {
      el.style.border = "solid black 2px";
      el.style.borderWidth = binding.value.width
      el.style.borderColor = binding.value.color
      el.style.borderStyle = binding.arg
      //roundという修飾子があればtrueを返す
      if (binding.modifiers.round) {
        el.style.borderRadius = "0.5rem"
      }
      if (binding.modifiers.shadow) {
        el.style.boxShadow = "0.2px 5px"
      }
    }
  }
}
</script>
```

注目すべきは

```js
filters: {
    lowerCase(value) {
      return value.toLowerCase()
    }
  },
```

filters:以下にフィルターを定義していく。
ちなみに、フィルターではthisを使うことができないので注意。


##複数のフィルターを連結


```vue
<h2>{{ title | upperCase | lowerCase }}</h2>
```

#ミックスイン

2つのdataオプションに同じプロパティがある時に、ミックスインを使うと、1度書くだけで良くなる。

まずは、任意のjsファイルにまとめたい処理を抜き出す

```js
export const tokyoNuber = {
  data(){
    return {
        title: "Hello!!",
        subTitle: "good morning!", 
        number: 0
    }
  },
  filters: {
    lowerCase(value) {
      return value.toLowerCase()
    }
  }
}
```

その際、export const 任意の名前 = {}とする

次に、このまとめた処理を使いたいコンポーネントでインポートする

```.vue
<template>
  <div>
    <h2>{{ title | lowerCase }}</h2>
    <p>{{ subTitle | upperCase }}</p>
    <button @click="number++">+1</button>
  </div>
</template>

<script>
//まずimportする
import { tokyoNumber } from "@/tokyoNumber"
export default {
  //mixins:以下に配列として指定。
  mixins: [tokyoNumber],
  
}
</script>
```

ちなみに、ミックスインとコンポーネント内のプロパティで同じプロパティを指定してしまった場合は、コンポーネントの方が優先される。

##グローバルミックスイン

グローバルミックスインを定義する時の注意点は、全てのVueインスタンスに適用されてしまうということ。

今回はmain.jsで定義する

```main.js
Vue.mixin({
  //ここにまとめたいプロパティなどを書く
})
```