1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[nuxt.js]カレンダーライブラリflatpickrを使って楽ちんカレンダー表示

1
Last updated at Posted at 2021-09-14

スクリーンショット 2021-09-14 18.20.00.png
初めてカレンダーライブラリのflatpickrを使ってみたので、その備忘録。
ちょっとした設定だけでカレンダーが実装できて大変嬉しい。

ざっくりかき4つのステップでいけます。
①flatpickrのインストール
②flatpickerのインポート
③テキストフィールドにidを指定
④scriptでオプションを指定

▼環境

  • macOS Big Sur 11.2.3
  • node v16.2.0
  • npm 7.20.0
  • nuxt.js @nuxt/cli v2.15.6
    また当方、フレームワークはvuetifyを使用しています!

①flatpickrのインストール

getting Started.
まずはnpm i -D flatpickrまたはyarn add flatpickrにてflatpickrをインストール。

CDNでの読み込みも可能です。その他方法のインストールは公式をご参照ください。
flatpickr公式

追記:
nuxt向けにはこんなのもあるみたいです。これを入れると後の実装が変わります。module追記する必要があると思います。
npm | nuxt-flatpickr

npm i nuxt-flatpickr

②flatpickerのインポート

<script>内にflatpickrを宣言します。default必要。

pages/Example.vue
<script>
const flatpickr = require('flatpickr').default
</script>

参考: stackflow | Why need default after require() method in Vue?

③テキストフィールドにidを指定

入力フォームを設置してidを指定します。

inputタグ(今回はvuetifyを使っているのでv-text-fieldを使用)など、入力フォームにidを設定し、data内でidを定義します(id: 'datePick')。

pages/Example.vue
<template>
  <div>
    <Header />
    <v-container>
      <v-text-field :id="id"></v-text-field>
    </v-container>
  </div>
</template>

<script>
const flatpickr = require('flatpickr').default
export default {
  data() {
    return {
      id: 'datePick',
    }
  },
}
</script>

もちろん、textfieldタグのidに直接定義しても大丈夫です。

pages/Example.vue
   <v-text-field id="datePick"></v-text-field>

④scriptでオプションを指定

pages/Example.vue
<script>
const flatpickr = require('flatpickr').default
export default {
  data() {
    return {
      id: 'datePick',
    }
  },
  mounted() {
    // DOMが描画されてからflatpickr呼び出し
    this.$nextTick(() => {
      this.flatpickr = flatpickr('#' + this.id, this.flatPickrConfig)
    })
  },
}
</script>

やったね!
スクリーンショット 2021-09-14 17.41.54.png

せっかくなので拡張してみる。

せっかくなので、親、子、孫、みたいな感じでデータを渡してみます。
getting Startedまでは同じです。

ファイル構成は、下記の通り。
親: pages/date/index.vue
子: components/molecules/ContentsCard.vue
孫: components/Atoms/DatePicker.vue

親で今日の日付を取得

親で今日の日付を取ってきて、初期値として表示。

index.vue
<template>
  <div>
    <Header />
    <v-container class="contents">
      <ContentsCard :today="today" />
    </v-container>
  </div>
</template>

<script>
export default {
  asyncData({ $dayjs }) {
    const dayjs = $dayjs()
    const today = dayjs.format('YYYY年MM月DD日')
    // console.log(today)
    return { today }
  },
}
</script>

スクリーンショット 2021-09-14 17.56.01.png
まっさら!

子ども(components/molecules/ContentsCard.vue)を作成

vuetifyのポップアップウィンドウはv-dialogでできます。
https://vuetifyjs.com/ja/components/dialogs/

ContentsCard.vue
<template>
  <div>
    <v-card class="mx-auto" min-width="360" outlined flat>
      <v-card-title>This it the flatpickr</v-card-title>
      <v-card-subtitle>Click the button then you'll see</v-card-subtitle>
      <v-card-text>
        <v-dialog v-model="dialog" width="500">
          <template #activator="{ on, attrs }">
            <v-btn
              color="primary"
              rounded
              elevation="false"
              v-bind="attrs"
              v-on="on"
            >
              open dialog
            </v-btn>
          </template>
          <v-card>
            <v-card-title class="text-h5"> flatpickr </v-card-title>

            <v-card-text> ここに孫のDatePicker.vueを入れるよ! 

              <v-divider></v-divider>
            </v-card-text>

            <v-card-actions>
              <v-spacer></v-spacer>
              <v-btn color="primary" text @click="dialog = false">
                close
              </v-btn>

            </v-card-actions>
          </v-card>
        </v-dialog>
      </v-card-text>
    </v-card>
  </div>
</template>

<script>
export default {
  data() {
    return {
      dialog: false,
    }
  },
}
</script>


スクリーンショット 2021-09-14 18.15.21.png

まだ孫を作成していないため、open dialogを押下してもテキストしかありません。
スクリーンショット 2021-09-14 18.20.00.png

孫(components/atoms/DatePicker.vue)を作成

先ほどのContentsCard.vueのテキストエリア
<v-card-text> ここに孫のDatePicker.vueを入れるよ! </v-card-text>の中身を、
孫のコンポーネント名に書き換えます。

ContentsCard.vue
            <v-card-text>
              <DatePicker3></DatePicker3>

              <v-divider></v-divider>
            </v-card-text>

今日の日付をデフォルトの表示として孫のテキストフィールドに表示させたいため、propsとして親から受け取った値を孫に渡しておきます。はい、これお小遣いね。

ContentsCard.vue

<DatePicker v-model="itemToday" label="日付を選択"></DatePicker>

// 適当なところで日付が取れているか確認
{{ itemToday }}

<script>
export default {
  props: {
    today: {
      type: String,
      default: '',
    },
  },
  data() {
    return {
      dialog: false,
      itemToday: '',
    }
  },
  mounted() {
    this.itemToday = this.today
  },
}
</script>

それではやっと孫の中身を作成し始めます。
何はともあれ土台と、先ほど子どもで受け取った今日の日付を受け取っておきます。
選択した日付はそのまま親に渡すデータになるので、v-modelはvalueとして値を取得後、computedで値をセットして$emitしておきます。(親は@inputで受け取れます。)

※v-modelによるプロパティのバインディングは、:value(部品の初期値を指定)と@input(データとしてサーバに送信)をまとめた等位構文なので。バインドしたプロパティに対して参照と更新の両方が発生。

参考: v-modelにオブジェクトをバインディングする場合のコンポーネント実装を考える

valueで複数型を指定しているのは、$dayjs()で渡される値がStringとNumberの可能性があるからです。
参考: Vue.js の props の type 指定時に String と Number の両方を許容させる

DatePicker.vue
<template>
  <div>
    <v-text-field v-model="innerValue" :label="label"></v-text-field>
  </div>
</template>

<script>
export default {
  props: {
    value: {
      type: [String, Number],
      default: '',
    },
    label: {
      type: String,
      default: '',
    },
  },
  computed: {
    innerValue: {
      get() {
        return this.value
      },
      set(val) {
        this.$emit('input', val)
      },
    },
  },
}
</script>


今日の日付を表示させられました!
スクリーンショット 2021-09-14 19.15.39.png

孫(components/atoms/DatePicker.vue)にflatpickrを実装!

前置きが長くなってしまったのでお忘れかもしれませんが…flatpickrを実装する上で必要なのは、
①flatpickrのインストール
②flatpickerのインポート
③テキストフィールドにidを指定
④scriptでオプションを指定

でした!

①はもうできているので、

②flatpickerのインポート

DatePicker.vue

const flatpickr = require('flatpickr').default

// export defaultの上

#### ③テキストフィールドにidを指定

そのままidの値を入れてもいいのですが、拡張性を持たせるためにプロパティで用意しておきます。

DatePicker.vue

<v-text-field :id="id" v-model="innerValue" :label="label"></v-text-field>

初期値を設定しておきます。

DatePicker.vue
<script>
export default {
  props: {
    // propsに追加
    id: {
      type: String,
      default: 'datePick',
    },
  },
</script>

#### ④scriptでオプションを指定

flatpickrの初期値と、オプションをオブジェクトで用意しておきます。日本語対応させたいので、flatpickrが用意している日本語もimportしておきます。
※オプションは公式をご参照ください。
https://flatpickr.js.org/options/

DatePicker.vue
<script>
import { Japanese } from 'flatpickr/dist/l10n/ja'
export default {
  data() {
    return {
      flatpickr: null,
      flatpickrConfig: {
        altInput: true,
        locale: Japanese,
        altFormat: 'Y年m月d日',
        dateFormat: 'Ymd',
      },
    }
  },
}
</script>

mountedのタイミングで、flatpickrを描画させます。
$nextTickはVueが用意している機能です。

Callbackを延期し、DOMの更新サイクル後に実行します。DOM更新を待ち受けるために、いくつかのデータを変更した直後に使用してください。
こちらを参考にしました。
Vue.nextTickのコードリーディング

DatePicker.vue
<script>

  mounted() {
    this.$nextTick(() => {
      this.flatpickr = flatpickr('#' + this.id, this.flatPickrConfig)
    })
  },
  methods: {},
}
</script>

表示できました!
スクリーンショット 2021-09-14 19.39.25.png

おまけ:オシャレにします。

お好みのスタイルを選ぶんだ! => 公式

scriptにテーマを追加するだけ!

<script>
import 'flatpickr/dist/themes/confetti.css'
</script>

初期値、オプション設定

flatpickrの基本は、データの初期値を用意して、オプションを設定するだけ。
私はvuetifyを使用しているため少しわかりにくいかもしれませんが、基本は下記の形です!

<script>
<input class="input" id="unchi" type="text" />

<script>
flatpickr("#unchi", { オプション });
</script>

オプションは公式から確認できます。 => オプション

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?