30
31

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.

Vue.jsのカレンダライブラリv-calendarを使って、日付ごとのデータをカレンダー上に表示

Last updated at Posted at 2019-08-26

概要

Vue.js上で動かせるカレンダーUIライブラリのv-calendarを使って、予めサーバ等から取得した日付ごとのオブジェクトをカレンダー上に突っ込む方法です。
公式ページはこちら

出力結果とソース

先に、出力結果です。
後述する日付ごとのデータを、カレンダー内に表示している内容となります。

スクリーンショット 2019-08-26 15.34.23.png

続いてこちらのソースです。
※事前に、npm install v-calenderをつかって、v-calendarをインストールしてください。

main.js
import Vue from 'vue'
import App from './App.vue'

import VCalendar from 'v-calendar'

Vue.use(VCalendar) 
Vue.config.productionTip = false

new Vue({
  render: h => h(App),
}).$mount('#app')
App.vue
<template>
  <div id="app">
    <calendar/>
  </div>
</template>

<script>
import calendar from './components/Calendar.vue'

export default {
  name: 'app',
  components: {
    calendar
  }
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
Calendar.vue
<template>
  <div>
    <v-calendar
    :columns="2"
    title-position="center"
    >
    <template slot='header-title' slot-scope='props'>
      {{props.yearLabel}}{{props.monthLabel}}
    </template>
    <template slot='day-content' slot-scope='props'>
      <div class="cell-header">
        {{props.day.day}}
      </div>
      <div class="cell-content">
      <template 
      v-if="dateList.some(date => date.ymd === dateToYYYYMMDD(props.day.date))">
        <div 
        class="cell-content-line" 
        v-for="content in getContentFromKey(dateToYYYYMMDD(props.day.date))" 
        v-bind:key="content">{{content}}
        </div>
        </template>
      </div>
    </template>
 
    </v-calendar>
  </div>
</template>

<script>
export default {
  name: 'calendar',
  data() {
    return {
      dateList: [
        {ymd: '20190923', contents: ['髪を切る','面談','靴を買う']},
        {ymd: '20190914', contents: ['結婚式']},
        {ymd: '20190901', contents: ['妹の誕生日']},
        {ymd: '20190817', contents: ['海に行く!', '野球の練習']}
      ]
    }
  },
  computed: {
  },
  methods: {
     dateToYYYYMMDD: function(date) {
      let y = date.getFullYear()
      let m = ('00' + (date.getMonth()+1)).slice(-2)
      let d = ('00' + date.getDate()).slice(-2)
      let result = y + '' + m + '' + d
      return result
    },
    getContentFromKey: function(key) {
      const target = this.dateList.find((date) => {
        return (date.ymd === key)
      })
      return target.contents
    }
  }
}
</script>

<style scoped>
.cell-content {
  text-align:left;
  width: 70px;
  height: 50px;
  font-size: 50%;
  /* border: 1px solid #efefef; */
}
.cell-content-line {
  border-bottom: 1px solid #efefef;
}
</style>

かんたんに解説

main.jsについては、Vueにv-calendarを読み込ませているだけです。
App.vueのtemplate内にて、今回カレンダーを作成したCalendar.vueコンポーネントを呼び出しています。
それでは、Calendar.vueをかんたんに解説します。


先にdataの部分を説明します。

  data() {
    return {
      dateList: [
        {ymd: '20190923', contents: ['髪を切る','面談','靴を買う']},
        {ymd: '20190914', contents: ['結婚式']},
        {ymd: '20190901', contents: ['妹の誕生日']},
        {ymd: '20190817', contents: ['海に行く!', '野球の練習']}
      ]
    }

このオブジェクトの配列が、今回表示したいデータとします。
ymdがkeyとなり、同じ日に複数のコンテンツが有る場合を加味しています。


続いて、templateの部分です。

    <v-calendar
    :columns="2"
    title-position="center"
    >

v-calenderを呼び出す際に、プロパティを指定しています。
今回は、2列のカレンダーとし、ヘッダを中央に寄せるような設定となっています。
どのようなプロパティが指定できるのかについては、公式に記載されていますので、見てみてください。


    <template slot='header-title' slot-scope='props'>
      {{props.yearLabel}}{{props.monthLabel}}
    </template>

v-calendarでは、カレンダーの中身を編集する際、パーツに応じたスコープ付きスロットを使用します。
上記のheader-titleというスコープは、カレンダーの年月日ヘッダが記載されている部分となります。
テンプレート内で{{props.yearLabel}}年{{props.monthLabel}}とすることで、2019年8月といったヘッダの表示に修正しています。(この記載をしないと、デフォルトのヘッダである”2019 08月”といった表示になります。)


    <template slot='day-content' slot-scope='props'>
      <div class="cell-header">
        {{props.day.day}}
      </div>
      <div class="cell-content">
      <template 
      v-if="dateList.some(date => date.ymd === dateToYYYYMMDD(props.day.date))">
        <div 
        class="cell-content-line" 
        v-for="content in getContentFromKey(dateToYYYYMMDD(props.day.date))" 
        v-bind:key="content">{{content}}
        </div>
        </template>
      </div>
    </template>

今回のキモとなる部分です。
まず、さきほどのheader-titleと同様に、今度はday-contentというスコープのスロットを設定します。day-contentは、カレンダーの日付の部分を表示する箇所となります。
公式を見ていただければわかるように、
props.dayというのはdayオブジェクトであり、更にその中にdayという日付の文字列がはいっています。
そのため、props.day.dayと指定することで、日付を取得しています。

v-if="dateList.some(date => date.ymd === dateToYYYYMMDD(props.day.date))"

の部分で、まずprops.day.dateから取得した日付オブジェクトがdateListに存在するかどうかを見ています。
存在している日付に限り、中の

        <div 
        class="cell-content-line" 
        v-for="content in getContentFromKey(dateToYYYYMMDD(props.day.date))" 
        v-bind:key="content">
          ・{{content}}
        </div>

が評価され、contentが描画されるようになっております。

まとめ

v-calendarの設定をつかってカレンダーをカスタマイズしてみましたが、
他にもたくさんのプロパティやイベントが存在するので、ぜひ一度使ってみてください。

今回の記法が冗長である等、改善部分があればぜひご指摘ください。

みていただきありがとうございました。😊

30
31
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
30
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?