10
2

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 1 year has passed since last update.

【Script SetUp】dayjsを使ったカレンダー作成【TypeScript】

Last updated at Posted at 2022-10-30

開発環境

MacBook Air (M1, 2020)
npm 8.18.0
"vue": "^3.2.13"
"dayjs": "^1.11.5"

本記事の内容

dayjsというライブラリを使ったカレンダーを作成します。

以下が目次です。

  • 使用するものの作成
  • カレンダーの作成
  • より詳しい紹介

では解説していきます。

使用するものの作成

①使用するイベントデータ
②使用する型定義

使用するイベントデータ

data
events:[
  { id: 1, name: "宿題", date: "2022-10-01", color:"blue"},
  { id: 2, name: "遊び", date: "2022-10-10", color:"limegreen"},
  { id: 3, name: "ミーティング", date: "2022-10-15", color:"deepskyblue"},
  { id: 4, name: "", date: "2022-10-20", color:"dimgray"},
  { id: 5, name: "デート", date: "2022-10-31", color:"navy"},
]

使用する型定義

型を用意します。

src/types/index.ts
export type EventItem={
    id: number,
    pet_id: number,
    health: string,
    detail: string,
    start: Date,
    end: Date,
    color: "blue"| "red"|"limegreen"|"deepskyblue"|"dimgray"|"navy"|"orange"|"teal"|"royalblue",
    isEditable: boolean
}

export type DateItem = {
    date: number
    month: string
    dayEvents: EventItem[]
}

カレンダーの作成

手順は以下の11個です。
①カレンダーの最初の日を取得する。
②カレンダーの最後の日を取得する。
③一ヶ月の週の数分の配列の作成する。
④③で作成した配列を取得する。
⑤フォーマットを整える
⑥前の月を表示する。
⑦後ろの月を表示する。
⑧数字から曜日に変更を行うメソッドを定義する。
⑨背景色を分けるためのプロパティを作成する。
➉イベントを取得する。
⑪日付が一致するイベントを取得し、配列として格納するメソッドする。

では以下のコードを見ていきましょう。

src/views/CalendarView.vue
<script setup lang="ts">
import dayjs from 'dayjs'
import { ref, computed } from 'vue'
import { EventItem } from '@/types/event';
import { useStore } from '../store'

const currentDate = ref(dayjs())

//①カレンダーの最初の日を取得する。
const getStartDate = () => {
    //月の初めの日を取得する
    let date = dayjs(currentDate.value).startOf("month");
    const youbiNum = date.day();
    //月の初めの日から日曜日までの差を算出し、日曜日の日を取得。
    return date.subtract(youbiNum, "days");
}
//②カレンダーの最後の日を取得する。
const getEndDate = () => {
    //月の最後の日を取得
    let date = dayjs(currentDate.value).endOf("month");
    const youbiNum = date.day();
    //月の初めの日から土曜日までの差を算出し、土曜日の日を取得。
    return date.add(6 - youbiNum, "days");
};
//③一ヶ月の週の数分の配列の作成
const getCalendar = () => {
  let startDate: dayjs.Dayjs;
  //月の初めの日
  startDate = getStartDate();
  //月最後の日
  const endDate = getEndDate();
  //カレンダーの縦軸を計算
  const weekNumber = Math.ceil(endDate.diff(startDate, "days") / 7);
  
  //空配列を用意
  let calendars: DateItem[][] = [];
  let calendarDate: dayjs.Dayjs;
  calendarDate = getStartDate();

//7日分の日にちデータをループで取得してweekRowにpush。そしてweekRowの配列をcalendarsにpush。それをカレンダーの縦軸回数繰り返す処理
  for (let week = 0; week < weekNumber; week++){
    const weekRow = [];
    for (let day = 0;  day < 7; day++) {
      let dayEvents: EventItem[] = getDayEvents(calendarDate)
      weekRow.push({
        date: calendarDate.get("date"),
        month: calendarDate.format("YYYY-MM")//背景色を分けるため追加
        dayEvents
      })
      calendarDate = calendarDate.add(1, "days");
    }
    calendars.push(weekRow);
  }
  return calendars;
}

//④③で作成した配列を取得
const calendars = computed(()=>{
  return getCalendar()
})

//⑤フォーマットを整える
const displayMonth = computed(()=>{
  return currentDate.value.format('YYYY[年]M[月]')
})

//⑥前の月を表示
const prevMonth = () => {
  currentDate.value= dayjs(currentDate.value).subtract(1, "month")
}

//⑦後ろの月を表示
const nextMonth = () => {
  currentDate.value = dayjs(currentDate.value).add(1, "month")
}

//⑧数字から曜日に変更を行うメソッドを定義
const youbi = (dayIndex: number) => {
  const week = ["", "", "", "", "", "", ""];
  return week[dayIndex];
}

//⑨背景色を分けるためのプロパティ
const currentMonth= computed(()=>{
  return currentDate.value.format('YYYY-MM')
})

const store = useStore()

//⑩イベントを取得
const events = computed<EventItem[]>(()=>{
  return store.getters['calendar/getEvents']
})

//⑪日付が一致するイベントを取得し、配列として格納するメソッド
const getDayEvents = (date: dayjs.Dayjs) => {
  return events.value.filter((event: EventItem)=> {
    let eventDate = dayjs(event.start).format('YYYY-MM-DD')
    let Date = date.format('YYYY-MM-DD')
    if(eventDate == Date) return true;
  });
}

</script>
<template>
  <div>
    <div class="content">
      <p>{{currentDate}}</p>
    <h3></h3>
    <h2>現在の日付:{{ displayMonth }}</h2>
    <div class="button-area">
      <button @click="prevMonth" class="button">前の月</button>
      <button @click="nextMonth" class="button">次の月</button>
    </div>
    <div class="calendar">
      <div class="calendar-weekly">
        <div class="calendar-youbi" v-for="n in 7" :key="n">
          {{ youbi(n-1) }}
        </div>
      </div>
      <div class="calendar-weekly" v-for="(week, index) in calendars" :key="index">
        <div class="calendar-daily" :class="{outside: currentMonth !== day.month}" v-for="(day, index) in week" :key="index">
          <div class="calendar-day">
            <p>{{ day.date }}</p>
          </div>
          <!--currnetMonthの値とday.monthの値が異なる場合のみstyleを適用-->
          <div v-for="dayEvent in day.dayEvents" :key="dayEvent.id" >
        <div class="calendar-event" :style="`background-color:${dayEvent.color}`" >
          <p>{{ dayEvent.health }}</p>
        </div>
      </div>
        </div>
      </div>
    </div>
  </div>
  </div>
</template>

<style>
 /* 全体調整*/
.content{
 /* 中央よせ*/
  margin:2em auto;
 /* 大きさ調整*/
  width:900px;
}
.button-area{
  margin:0.5em 0;
}
 /* ボタン調整*/
.button{
  padding:4px 8px;
  margin-right:8px;
}
.calendar{
 /* 上横線*/
  border-top:1px solid #E0E0E0;
 /* カレンダーフォントサイズ*/
  font-size:0.8em;
}
.calendar-weekly{
 /* 週ごとに横並び*/
  display:flex;
 /* 左縦線*/
  border-left:1px solid #E0E0E0;
}

/* 日にちのスタイル*/
.calendar-daily{
  /* 横幅*/
  flex:1;
 /* 大きさ調節*/
  min-height:125px;
 /* 右縦線*/
  border-right:1px solid #E0E0E0;
 /* 下横線*/
  border-bottom:1px solid #E0E0E0;
}

/* 曜日のスタイル*/
.calendar-youbi{
  /* 横幅調節*/
  flex:1;
  /* 縦線*/
  border-right:1px solid #E0E0E0;
}

/* 背景色*/
.outside{
  background-color: #f7f7f7;
}
 /* イベント調整*/
.calendar-event{
 /* フォント色付け*/
  color:white;
  line-height:25px;
 /* 丸みを帯びさせる*/
  border-radius:4px;
}
</style>

より詳しい解説

ちょっとわかりづらい、8、9、10の3つのの3つについてより詳しい解説していきます。

数字から曜日に変更を行うメソッドを定義

タイトルの通り、数字を曜日に変更するメソッドです。
v-forを使い、7を順番に展開。
youbiメソッドを実行して数字を曜日に変更しています。
forで展開する場合、1から始まるので、-1としています。

src/views/CalendarView.vue
<script setup lang="ts">
const youbi = (dayIndex: number) => {
  const week = ["", "", "", "", "", "", ""];
  return week[dayIndex];
}
</script>
<template>
    <div class="calendar">
      <div class="calendar-weekly">
        <div class="calendar-youbi" v-for="n in 7" :key="n">
          {{ youbi(n-1) }}
        </div>
</template>

背景色を分けるためのプロパティ

ここでの目的は、currentMonthとの比較です。
そのためにフォーマットを整えます。

src/views/CalendarView.vue
<script setup lang="ts">
const currentMonth= computed(()=>{
  return currentDate.value.format('YYYY-MM')
})
const getCalendar = () => {
    //省略
  
  let calendars: DateItem[][] = [];
  let calendarDate: dayjs.Dayjs;
  calendarDate = getStartDate();

  for (let week = 0; week < weekNumber; week++){
    const weekRow: DateItem[] = [];
    for (let day = 0;  day < 7; day++) {
      let dayEvents: EventItem[] = getDayEvents(calendarDate)
      weekRow.push({
        date: calendarDate.get("date"),
        month: calendarDate.format("YYYY-MM")//背景色を分けるため追加
        dayEvents
      })
      calendarDate = calendarDate.add(1, "days");
    }
    calendars.push(weekRow);
  }
  return calendars;
}
</script>
<template>
    <!--currentMonthとday.monthが異なる場合のみcssを適用-->
    <div class="calendar-daily" :class="{outside: currentMonth !== day.month}" v-for="(day, index) in week" :key="index">
        <div class="calendar-day">
            <p>{{ day.date }}</p>
        </div>
</template>

日付が一致するイベントを取得し、配列として格納するメソッド

イベントという配列に格納されている情報を、カレンダーの日付と一致する場合に渡す処理を行なっています。

src/views/CalendarView.vue
<script setup lang="ts">

const getCalendar = () => {
    //省略
  
  let calendars: DateItem[][] = [];
  let calendarDate: dayjs.Dayjs;
  calendarDate = getStartDate();

  for (let week = 0; week < weekNumber; week++){
    const weekRow: DateItem[] = [];
    for (let day = 0;  day < 7; day++) {
      let dayEvents: EventItem[] = getDayEvents(calendarDate)
      weekRow.push({
        date: calendarDate.get("date"),
        month: calendarDate.format("YYYY-MM")//背景色を分けるため追加
        dayEvents
      })
      calendarDate = calendarDate.add(1, "days");
    }
    calendars.push(weekRow);
  }
  return calendars;
}
//渡されてきたcurrentDateとイベントに格納されている日付データと一致する場合にその情報を配列にして渡す。
const getDayEvents = (date: dayjs.Dayjs) => {
  return events.value.filter((event: EventItem)=> {
    let eventDate = dayjs(event.start).format('YYYY-MM-DD')
    let Date = date.format('YYYY-MM-DD')
    if(eventDate == Date) return true;
  });
}
</script>
10
2
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
10
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?