やりたいこと
- Vue.js 3 で作った SPA で、デイトピッカーを使いたい。
- flatpickr/flatpickr: lightweight, powerful javascript datetimepicker with no dependencies がよさそうで、今回これをとりあげる。
- 公式ドキュメント → Introduction
- 簡単に使いたいので、デイトピッカーのシングルファイルコンポーネント (SFC) を用意したい。
- 簡単に使えそうなラッパーライブラリ ankurk91/vue-flatpickr-component: Vue.js component for Flatpickr datetime picker があるので、これを利用してみた。
ちなみに、 Vue.js 3 でラップしてコンポーネント化した Dropzone.js にちょっとしたカスタマイズをいくつか加えた – oki2a24 あたりの続きになります。
完成コード
まず、依存パッケージに npm install vue-flatpickr-component --save-dev
で追加しました。
diff --git a/laravel/package.json b/laravel/package.json
index 89c9726..81998a8 100644
--- a/laravel/package.json
+++ b/laravel/package.json
@@ -32,6 +32,7 @@
"select2": "^4.1.0-rc.0",
"select2-theme-bootstrap4": "^1.0.0",
"vue": "^3.0.11",
+ "vue-flatpickr-component": "^9.0.3",
"vue-loader": "^16.2.0",
"vue-router": "^4.0.6",
"vue-template-compiler": "^2.6.12",
続いて、 Vue Router に今回試すためのページを追加しました。
diff --git a/laravel/resources/js/router/index.js b/laravel/resources/js/router/index.js
index eacc035..7f7c22e 100644
--- a/laravel/resources/js/router/index.js
+++ b/laravel/resources/js/router/index.js
@@ -1,6 +1,7 @@
import { createRouter, createWebHistory } from "vue-router";
import ExampleComponent from "../components/ExampleComponent.vue";
import SampleDropzone from "../views/SampleDropzone.vue";
+import SampleVueFlatpickr from "../views/SampleVueFlatpickr.vue";
import SampleSelect2 from "../views/SampleSelect2.vue";
import Vue3Dropzone from "../views/Vue3Dropzone.vue";
const Home = { template: "<div>Home</div>" };
@@ -22,6 +23,11 @@ const routes = [
name: "SampleDropzone",
component: SampleDropzone,
},
+ {
+ path: "/sample_vue_flatpickr",
+ name: "SampleVueFlatpickr",
+ component: SampleVueFlatpickr,
+ },
{
path: "/sample_select2",
name: "SampleSelect2",
ここからはコード全体で、まずは laravel/resources/js/views/SampleVueFlatpickr.vue
です。このページから、ラップした SFC を呼び出しています。
- デイトピッカーを2つ呼び出す形にしている。これは、デイトピッカーを当てるタグの id 等が重複するなどが原因で、片方のデイトピッカーを起動するともう片方も連動して起動してしまうといった現象が起きないことを確認するため。
<template>
<div class="container">
<h1>SampleVueFlatpickr</h1>
<basee-vue-flatpickr v-model="date1" />
<basee-vue-flatpickr v-model="date2" />
</div>
</template>
<script>
import BaseeVueFlatpickr from "../components/BaseVueFlatpickr.vue";
import { ref } from "vue";
export default {
name: "SampleVueFlatpickr",
components: { BaseeVueFlatpickr },
setup() {
return {
date1: ref(""),
date2: ref(""),
};
},
};
</script>
laravel/resources/js/components/BaseVueFlatpickr.vue
です。ラップした SFC であり、利用側から呼び出されます。
- flatpickr の locale を設定して日本語化している。
- 日本語化する際、 import した Japanese オブジェクトの firstDayOfWeek プロパティ (週の始まりの曜日) に値を設定してカスタマイズしている。
<style>
でカレンダーの土日に色をつけている。 【flatpickr】日本語化の設定 – CHEATPARK – 神戸三宮のシステム開発会社CHEAT をそのまま使わせていただいた。もしかしたらもう少し短く書けるのかもしれないが、試していない。- props として受付ける値の種類として、 type ではなく validator を使ってみた。ラップしたライブラリと同じことをしてみた。ただし、もしかしたら type を複数指定すれば同じことが実現できるのかもしれない。 vue-flatpickr-component/component.js at master · ankurk91/vue-flatpickr-component
<template>
<flat-pickr
:config="config"
:model-value="modelValue"
@update:modelValue="updateModelValue"
></flat-pickr>
</template>
<script>
import { Japanese } from "flatpickr/dist/l10n/ja.js";
import flatPickr from "vue-flatpickr-component";
export default {
name: "BaseVueFlatpickr",
components: { flatPickr },
props: {
modelValue: {
default: null,
required: true,
validator(value) {
return (
value === null ||
value instanceof Date ||
typeof value === "string" ||
value instanceof String ||
value instanceof Array ||
typeof value === "number"
);
},
},
},
emits: ["update:modelValue"],
setup(props, { emit }) {
Japanese.firstDayOfWeek = 1;
const config = {
locale: Japanese,
};
const updateModelValue = (modelValue) => {
emit("update:modelValue", modelValue);
};
return { config, updateModelValue };
},
};
</script>
最後に、 laravel/resources/sass/app.scss
です。 BaseVueFlatpickr のためのスタイルです。 <style scoped>
を試みてみましたけれども、うまくいかずシステム全体へ反映するしかないと結論づけましたので、ふさわしい場所である laravel/resources/sass/app.scss
へ記述いたしました。追加した部分のみを抜粋して掲載いたします。
// flatpickr
@import "~flatpickr/dist/flatpickr.css";
/* 日曜日:赤 */
.flatpickr-calendar
.flatpickr-innerContainer
.flatpickr-weekdays
.flatpickr-weekday:nth-child(7n),
.flatpickr-calendar
.flatpickr-innerContainer
.flatpickr-days
.flatpickr-day:not(.flatpickr-disabled):not(.prevMonthDay):not(.nextMonthDay):nth-child(7n) {
color: red;
}
/* 土曜日:青 */
.flatpickr-calendar
.flatpickr-innerContainer
.flatpickr-weekdays
.flatpickr-weekday:nth-child(6),
.flatpickr-calendar
.flatpickr-innerContainer
.flatpickr-days
.flatpickr-day:not(.flatpickr-disabled):not(.prevMonthDay):not(.nextMonthDay):nth-child(7n
-
1) {
color: blue;
}
おわりに
次のページも参考になりました!ありがとうございます。
もっと複雑なことをやりたい、例えば祝日の情報を flatpickr へ与え、選択できなくする、という時に、もしかしたら今回使用したライブラリは使えないのかもしれません。ですので、 Flatpicker を直接ラップした SFC にも挑戦できたらさらに自由度が広がりそうだ、と思いました。
以上です。