やりたいこと
- 日々の献立表をカレンダーを使って表示させる
- カレンダー表示時にAPIを実行し、献立を取得する
今回はVuetifyを使っていたので、v-calendarを使って実現しました。
Vuetifyの環境構築についてはこちらのページに記載しています。
ソースコードの構成
構成としてはsrc/views
配下にカレンダー表示用ページを作り、
実際のカレンダー表示はsrc/component
にコンポーネント化し、viewに組み込みます。
カレンダーコンポーネント
まずは、カレンダー表示用コンポーネントを作成します。
<template>
<v-row justify="center" style="height: 600px">
<v-col cols="10">
<v-sheet tile height="6vh" color="grey lighten-3" class="d-flex align-center">
<v-btn outlined small class="ma-4" @click="setToday">
今日
</v-btn>
<v-btn icon @click="$refs.calendar.prev()">
<v-icon>mdi-chevron-left</v-icon>
</v-btn>
<v-btn icon @click="$refs.calendar.next()">
<v-icon>mdi-chevron-right</v-icon>
</v-btn>
<v-toolbar-title>{{ title }}</v-toolbar-title>
</v-sheet>
<v-calendar
ref="calendar"
v-model="value"
locale="ja-jp"
:events="events"
:day-format="(timestamp) => new Date(timestamp.date).getDate()"
:month-format="(timestamp) => (new Date(timestamp.date).getMonth() + 1) + ' /'"
@click:event="clickEvent"
@click:date="clickDay"
></v-calendar>
</v-col>
</v-row>
</template>
<script>
import { mapActions } from "vuex";
import moment from "moment";
export default {
name: "CalendarComponent",
data() {
return {
value: moment().format("yyyy-MM-DD"),
};
},
props: {
events: [],
},
methods: {
...mapActions("calendar-store", [
"setSelectedDate",
]),
setToday() {
this.value = moment().format("yyyy-MM-DD");
},
clickEvent({ event }) {
this.$emit("clickEvent");
this.setSelectedDate(event.start);
},
clickDay({ date }) {
this.$emit("clickDay");
this.setSelectedDate(date);
},
},
computed: {
title() {
return moment(this.value).format("yyyy年 M月");
},
},
};
</script>
以下で細かく説明します。
カレンダーの表示
<v-calendar
:events="events"
></v-calendar>
カレンダーに表示するデータは:events
にて渡します。
今回はページ側から受け渡しするために、popsに定義しました。
props: {
events: [],
},
月の遷移ボタン
<v-btn outlined small class="ma-4" @click="setToday">
今日
</v-btn>
<v-btn icon @click="$refs.calendar.prev()">
<v-icon>mdi-chevron-left</v-icon>
</v-btn>
<v-btn icon @click="$refs.calendar.next()">
<v-icon>mdi-chevron-right</v-icon>
</v-btn>
<v-toolbar-title>{{ title }}</v-toolbar-title>
上記はカレンダーのツールバーに「今日」「<」「>」の3つのボタンと「年月」を並べて表示させています。
<v-calendar
v-model="value"
:day-format="(timestamp) => new Date(timestamp.date).getDate()"
:month-format="(timestamp) => (new Date(timestamp.date).getMonth() + 1) + ' /'"
></v-calendar>
v-model
に表示させる日付を渡します。
day-format
とmonth-format
は日本語表記に変更しています。
data() {
return {
value: moment().format("yyyy-MM-DD"),
};
},
v-model
に渡すvalue
はdata()
に定義し、初期値は本日日付を設定しています。(momentを使用)
methods: {
setToday() {
this.value = moment().format("yyyy-MM-DD");
},
「今日」ボタンを押した場合はvalue
値に本日日付が設定され、今日のカレンダーが表示されます。
v-btn
の$refs.calendar.prev()
および@click="$refs.calendar.next()
は
value
にそれぞれ前月末日、翌月初日が設定され、カレンダーが遷移します。
computed: {
title() {
return moment(this.value).format("yyyy年 M月");
},
},
ツールバーの日付部分に表示されている年月を算出しています。
イベント処理
<v-calendar
@click:event="clickEvent"
@click:date="clickDay"
></v-calendar>
event
はカレンダーのイベントをクリックした際に実行されるメソッドです。
date
はカレンダーの日付をクリックした際に実行されるメソッドです。
method: {
clickEvent({ event }) {
this.$emit("clickEvent");
this.setSelectedDate(event.start);
},
clickDay({ date }) {
this.$emit("clickDay");
this.setSelectedDate(date);
},
}
どちらも親コンポーネントのメソッドをemitするようにしました。
this.setSelectedDate();
は日付をストアに保持しています。
(今回はストアの説明は省略します)
カレンダービュー
次に、コンポーネントの親である、カレンダー表示用のviewを作成します。
<template>
<div id="calendar">
<v-container>
<CalendarComponent
v-on:clickDay="onCategory"
v-on:clickEvent="onMenuOfDay"
:events="schedule"
></CalendarComponent>
</v-container>
</div>
</template>
<script>
import CalendarComponent from "@/components/CalendarComponent";
import MenuOfDayDialogComponent from "@/components/MenuOfDayDialogComponent";
import { mapActions, mapGetters } from "vuex";
export default {
name: "Calendar",
components: {
CalendarComponent,
MenuOfDayDialogComponent,
},
data() {
return {
isShowMenuOfDay: false,
schedule: [],
};
},
async created() {
Promise.all([
this.getSchedule().then((response) => {
this.schedule = response.data;
this.setScheduleList(response.data);
}),
]);
},
methods: {
...mapActions("calendar-store", [
"getSchedule",
"setScheduleList",
]),
onMenuOfDay() {
this.isShowMenuOfDay = true;
},
onMenuOfDayClose() {
this.isShowMenuOfDay = false;
},
},
};
</script>
以下で細かく説明します。
カレンダーコンポーネント
<template>
<div id="calendar">
<v-container>
<CalendarComponent
v-on:clickDay="onCategory"
v-on:clickEvent="onMenuOfDay"
:events="schedule"
></CalendarComponent>
</v-container>
</div>
</template>
カレンダーコンポーネントを使用しています。
v-on
にてカレンダーの日付およびイベントがクリックされた際に、emitされるメソッドを定義しています。
カレンダーコンポーネントのevents
にschedule
を渡しています。
初期表示
async created() {
Promise.all([
this.getSchedule().then((response) => {
this.schedule = response.data;
this.setScheduleList(response.data);
}),
this.getMenu().then((response) => {
this.setMenuList(response.data);
}),
]);
},
カレンダービューファイルが構成された際に、APIにて献立表およびメニューリストを取得しています。
APIはストア経由で取得されるようにしています。(ストアの説明は省略します)
献立表はschedule
に保持されます。
なお、APIで返却される情報は以下のようになっています。
[
{
"name": "玉子雑炊",
"start": "2022-05-01",
"end": "2022-05-01",
"color": "red",
},
{
"name": "麻婆春雨",
"start": "2022-05-09",
"end": "2022-05-09",
"color": "blue",
},
{
"name": "小松菜ときのこのお浸し",
"start": "2022-05-10",
"end": "2022-05-10",
"color": "green",
},
]
- name: イベントに表示される名前
- start: イベントの開始日
- end: イベントの終了日
- color: イベントの背景色
通常のカレンダーの使い方としてはイベントの開始日と終了日をstartとendにしますが、
今回は同日を設定することで、その日のみにメニューが表示されるようにしました。
イベント処理
onMenuOfDay() {
this.isShowMenuOfDay = true;
},
onMenuOfDayClose() {
this.isShowMenuOfDay = false;
});
},
イベントがクリックされた際のメソッドの挙動です。
カレンダー機能はイベントが多いと2 more
のように省略されるため、
今回はダイアログでその日のメニュー一覧が表示されるようにしました。
MenuOfDayDialogComponent
がダイアログで表示されるようになっていますが、割愛します。