15
9

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 5 years have passed since last update.

v-date-pickerをカスタマイズしてbirthday-pickerを作る

Last updated at Posted at 2019-12-18

TL;DR

  • VuejsのUIフレームワークであるVuetifyを使っていい感じの誕生日入力フォームを作成する
  • 以下を満たすものとする
    • 日本語対応
    • 日付の「日」は取る
    • 年から選択
    • 最初に年を選択するとき、1995年からになるようにする
    • 日付範囲制限(未来や古すぎる日付を誕生日に設定できない)
    • 日付を選択と同時にpickerを閉じる

動作環境

Vue.js v2.x
Vuetify v2.1.14

できたもの

解説

  • 日本語対応
    • v-date-pickerのlocaleプロパティを設定
  • 日付の「日」は取る
    • v-date-pickerのday-formatプロパティを設定
  • 日付範囲制限(未来や古すぎる日付を誕生日に設定できない)
    • max, minプロパティを設定
  • 最初に年を選択するとき、1995年からになるようにする
    • picker-dateプロパティを制御する必要がある
    • picker-dateではpickerの値をコントロールできる
    • そのため、v-modelでbindされたdateオブジェクトを触らずpickerについてのみ触ることができる
      <v-date-picker
        ref="picker"
        locale="jp-ja"
        v-model="date"
        :day-format="date => new Date(date).getDate()"
        :max="new Date().toISOString().substr(0, 10)"
        :picker-date="pickerDate"
        min="1950-01-01"
        @change="save"
      ></v-date-picker>
  • 年から選択
    • v-menuにバインドしたmenuをwatchし、v-date-pickerのactivePickerを制御する。
    • menuを選ばれたタイミングのみでactivePickerをYEAR指定にしないと、ずっと年選択になったりする
    • 選び始めたらpickerDateを初期化しないと、ユーザが入力してもpickerDateの値になってしまうので注意
  watch: {
    menu (val) {
      val && setTimeout(() => (
        // 年から選ぶようにする
        this.$refs.picker.activePicker = 'YEAR',
        // 選び始めたら初期化
        this.pickerDate = null
      ))
    },
  },
  • 日付を選択と同時にpickerを閉じる
    • 日付を選択したとき = v-date-pickerの@changeが発火するタイミング
    • その際、pickerDateと選択したdateを同期させないと、もう一度誕生日を選びなおした時に前回の日付が初期値として機能してくれないので注意
  methods: {
    save (date) {
      this.$refs.menu.save(date)
      // 再入力に備えて、入力が終わったら同期する
      this.pickerDate = date;
    },
  },

感想

v-date-pickerは抽象的な作りをしていて、開発者が用意されたプロパティやコンポーネントをよく調べる必要があります。
そのため、必然的にVueコンポーネントの学びを多く得られると思いました。

ぜひ、v-date-pickerもといVuetifyを触ってみてください!

付録

今回のコード

template


<div id="app">
  <v-app id="inspire">
    <v-menu
      ref="menu"
      v-model="menu"
      :close-on-content-click="false"
      transition="scale-transition"
      offset-y
      full-width
      min-width="290px"
    >
      <template v-slot:activator="{ on }">
        <v-text-field
          v-model="date"
          label="誕生日を入力"
          prepend-icon="event"
          readonly
          v-on="on"
        ></v-text-field>
      </template>
      <v-date-picker
        ref="picker"
        locale="jp-ja"
        v-model="date"
        :day-format="date => new Date(date).getDate()"
        :max="new Date().toISOString().substr(0, 10)"
        :picker-date="pickerDate"
        min="1950-01-01"
        @change="save"
      ></v-date-picker>
    </v-menu>
  </v-app>
</div>

script

new Vue({
  el: '#app',
  vuetify: new Vuetify(),
  data: () => ({
    date: null,
    menu: false,
    // pickerの初期値(95年から年が選べるようになる)
    pickerDate: '1995-1-1',
  }),
  watch: {
    menu (val) {
      val && setTimeout(() => (
        // 年から選ぶようにする
        this.$refs.picker.activePicker = 'YEAR',
        // 選び始めたら初期化
        this.pickerDate = null
      ))
    },
  },
  methods: {
    save (date) {
      this.$refs.menu.save(date)
      // 再入力に備えて、入力が終わったら同期する
      this.pickerDate = date;
    },
  },
})
15
9
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
15
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?