カスタマイズ性抜群の日付選択ライブラリ「Vue Datepicker 」を使ってみた

## はじめに
Vue3.jsの開発で「Vue Datepicker」というライブラリを使ってみたので、そのときのことをまとめます。
- [ドキュメント](https://vue3datepicker.com/installation/)

## 導入
### インストール
#### npm
```console
npm install @vuepic/vue-datepicker
```
#### yarn
```console
yarn add @vuepic/vue-datepicker
```

### 初期設定
``main.js``からコンポーネントの登録を行います。コードは[ドキュメント](https://vue3datepicker.com/installation/#global)からそのまま引っ張ってきました。 
```js:main.js
import { createApp } from "vue";
import App from './App.vue';

// Vue Datepickerに関するimport
import VueDatePicker from '@vuepic/vue-datepicker';
import '@vuepic/vue-datepicker/dist/main.css'

const app = createApp(App);
// Vue Datepickerのコンポーネントを登録
app.component('VueDatePicker', VueDatePicker);

app.mount('#app');
```

## 実際に使ってみる
今回はVue Datepickerを使って、今月の日付のみ選択可能なカレンダーを作成してみます。
### 基本的な使い方
VueDatepickerは普通のVueコンポーネントなので、他のコンポーネントと使い方は同じです。
```vue:DatePicker.vue
<template>
  <div class="date-picker">
    <!-- 他のコンポーネントと一緒 -->
    <VueDatePicker />
  </div>
</template>

<style scoped>
/* 最低限のstyle */
.date-picker {
  margin: 60px auto 0;
  width: 50%;
}
</style>

```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2664008/abc3e988-b58f-aea0-fc7e-2993d4b8be85.png" width=450>

### v-modelでバインドしてみる
``input``タグと同様、``v-model``で入力値をバインドすることができます。``style``タグは今回のテーマに関係ないので、以降省略します。
```vue:DatePicker.vue
<template>
  <div class="date-picker">
    <!-- v-modelを使ってバインド -->
    <VueDatePicker v-model="inputDate" />
    {{ inputDate }}
  </div>
</template>

<script>
import { defineComponent } from '@vue/composition-api';
import { ref } from 'vue';

export default defineComponent({
  setup() {
    const inputDate = ref();

    return {
      inputDate,
    };
  },
});
</script>
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2664008/93310c3d-fe9f-e79f-cff6-307cd9d45aac.png" width=450>

### フォーマットを変更してみる
画面に表示される日付のフォーマットは``format``、``v-model``でバインドする値のフォーマットは``model-type``で指定します。
コンポーネントの属性を指定するだけで簡単にカレンダーをカスタマイズできます。
```vue:DatePicker.vue
<template>
  <div class="date-picker">
    <!-- 属性を指定するだけ -->
    <VueDatePicker
      v-model="inputDate"
      format="yyyy/MM/dd"
      model-type="yyyy-MM-dd"
    />
    {{ inputDate }}
  </div>
</template>

<script>
import { defineComponent } from '@vue/composition-api';
import { ref } from 'vue';

export default defineComponent({
  setup() {
    const inputDate = ref();

    return {
      inputDate,
    };
  },
});
</script>
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2664008/0ad12172-e105-5afb-1920-0cf6b8ac6ad1.png" width=450>

### カレンダーの見た目をカスタマイズする
カレンダーを次のようにカスタマイズしてみます。
- 英語表記から日本語表記に変更する
- 日付をクリックするだけで自動的にカレンダーを閉じるようにする
    - デフォルトの設定だと、「Select」ボタンを押さないと更新されない
- 日曜日が一番左に来るようにする
- 時間の入力は必要ないのでなくす
- 今日の日付のマークを外す

#### 英語から日本語への表記変更
``locale``を指定することで実現できます。日本語の場合は``"ja"``と指定しましょう。

#### 自動的にカレンダーを閉じるようにする
``auto-apply``を追加すると実現できます。

#### カレンダーの一番左に来る曜日の変更
``week-start``を指定することで実現できます。指定するときは、日曜日が``"0"``、月曜日が``"1"``、・・・という風に``"0"``から``"6"``の文字列で指定します。

#### 時間入力の非表示
``enable-time-picker``を指定することで実現できます。非表示にする場合は``false``にしましょう。

#### 今日の日付のマークを外す
``no-today``を追加すると実現できます。

```vue:DatePicker.vue
<template>
  <div class="date-picker">
    <!-- 属性を指定するだけ -->
    <VueDatePicker
      v-model="inputDate"
      format="yyyy/MM/dd"
      locale="ja"
      model-type="yyyy-MM-dd"
      week-start="0"
      :enable-time-picker="false"
      no-today
    />
    {{ inputDate }}
  </div>
</template>

<script>
import { defineComponent } from '@vue/composition-api';
import { ref } from 'vue';

export default defineComponent({
  setup() {
    const inputDate = ref();

    return {
      inputDate,
    };
  },
});
</script>
```

#### 変更前
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2664008/82f84959-b919-be28-2f29-2583d6313ab0.png" width=450>

#### 変更後
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2664008/0594b4ef-c959-b2a0-8695-f198bf1d2170.png" width=450>

### 今月以外の日付を指定できないようにしてみる
``disable-month-year-select``を追加することで、カレンダー上部の矢印が非表示になり移動できなくなります。
しかし、これだけだとスクロールによって前後の月に移動できるので、`month-change-on-scroll`に``false``を指定してスクロールも無効にします。
さらに``hide-offset-dates``を追加すると、前後の月の日付を非表示にできます。

```vue:DatePicker.vue
<template>
  <div class="date-picker">
    <VueDatePicker
      v-model="inputDate"
      format="yyyy/MM/dd"
      locale="ja"
      model-type="yyyy-MM-dd"
      week-start="0"
      :enable-time-picker="false"
      :month-change-on-scroll="false"
      auto-apply
      disable-month-year-select
      hide-offset-dates
      no-today
    />
    {{ inputDate }}
  </div>
</template>

<script>
import { defineComponent } from '@vue/composition-api';
import { ref } from 'vue';

export default defineComponent({
  setup() {
    const inputDate = ref();

    return {
      inputDate,
    };
  },
});
</script>
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2664008/eb0a2493-9823-7169-5094-adc7af8c2c86.png" width=450>

### 土日の色を変更する
``day-class``に``class``名を指定することで、日付の各要素に新しい``class``を追加できます。今回は関数を使うことで、条件を満たす日付に特定の``class``を追加します。

#### 注意
新しく追加するstyleは、``scoped``の``style``タグに書かないでください。``<VueDatePicker />``は別のコンポーネントなので、styleが適用されません。

```vue:DatePicker.vue
<template>
  <div class="date-picker">
    <VueDatePicker
      v-model="inputDate"
      format="yyyy/MM/dd"
      locale="ja"
      model-type="yyyy-MM-dd"
      week-start="0"
      :day-class="getDayClass"
      :enable-time-picker="false"
      :month-change-on-scroll="false"
      auto-apply
      disable-month-year-select
      hide-offset-dates
      no-today
    />
    {{ inputDate }}
  </div>
</template>

<script>
import { defineComponent } from '@vue/composition-api';
import { ref } from 'vue';

export default defineComponent({
  setup() {
    const inputDate = ref();
    
    // 条件分岐が必要なので、関数の戻り値を利用
    const getDayClass = (date) => {
      const weekDay = new Date(date).getDay();
      if (weekDay == 6) {
        // 土曜日の場合、classに"saturday"を追加
        return 'saturday';
      }
      if (weekDay == 0) {
        // 日曜日の場合、classに"sunday"を追加
        return 'sunday';
      }
      return '';
    };

    return {
      inputDate,
      getDayClass,
    };
  },
});
</script>

<style>
/* scopedの中には書かない */
.saturday {
  color: #0000ff;
}
.sunday {
  color: #ff0000;
}
</style>

<style scoped>
.date-picker {
  margin: 60px auto 0;
  width: 50%;
}
</style>
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2664008/67cdab63-83b8-5901-943c-7ab2f0ca0c8b.png" width=450>

とりあえずこれで完成です。

## 終わりに
このようにVue Datepickerは、コンポーネントに属性を追加していくだけで簡単にカレンダーをカスタマイズできます。
その上、カスタマイズの幅がとても広く、望みのカレンダーを実現できる可能性が高いです。
この記事に書いたこと以外にもたくさんのことができるので、[ドキュメント](https://vue3datepicker.com/props/modes/)を見てぜひ使ってみてください。