各バージョン
- react: 17.0.2
- @mui/material: 5.2.7
- moment: 2.29.1
カレンダーの作成
Material-UIとReactで下記のようなカレンダを作成します。
ほとんどCSSで作成しているのでHTMLとCSSだけでもできますが。
コード全体
import React from 'react';
import moment from 'moment';
import Box from '@mui/material/Box';
const Calendar = React.memo( () => {
const start = moment().startOf('month'); // 月初めの日付
const end = moment(start).endOf('month'); // 月終わりの日付
const calendar = [];
// 曜日合わせのループ
[...Array(Number(start.format('d')))].map((_, i) => calendar.push(<Box key={i}></Box>));
// 日付のループ
while(start.unix() <= end.unix()) {
calendar.push(<Box sx={{ aspectRatio: '1 / 1'}} key={start.format('MD')}>{start.format('D')}</Box>)
start.add(1, 'days');
}
return(
<>
<Box sx={{
width: '100%',
textAlign: 'center',
}}>{end.format('YYYY年M月')}</Box>
<Box sx={{
width: '100%',
display: 'grid',
gridAutoFlow: 'row',
gridTemplateColumns: 'repeat(7, 1fr)',
gap: 0,
}}>
<Box sx={{ textAlign: 'center', color: '#f00' }}>日</Box>
<Box sx={{ textAlign: 'center' }}>月</Box>
<Box sx={{ textAlign: 'center' }}>火</Box>
<Box sx={{ textAlign: 'center' }}>水</Box>
<Box sx={{ textAlign: 'center' }}>木</Box>
<Box sx={{ textAlign: 'center' }}>金</Box>
<Box sx={{ textAlign: 'center', color: '#00f' }}>土</Box>
{calendar}
</Box>
</>
);
});
Calendar.displayName = 'Calendar';
export default Calendar;
日付の計算
const start = moment().startOf('month'); // 月初めの日付
const end = moment(start).endOf('month'); // 月終わりの日付
その月の初めの日と終わりの日を計算します。
2022年3月ならstart:2022年3月1、end:2022年3月31日になります。
// 曜日合わせのループ
[...Array(Number(start.format('d')))].map((_, i) => calendar.push(<Box key={i}></Box>));
カレンダーの始まりは日曜日ですが、毎月1日が日曜日になるとは限らないので
日曜日以外の場合は空のBoxを配置して曜日を合わせる処理です。
moment().format(‘d’)で曜日の番号(0:日~6:土)が取得できるので
その分の空のBoxを配置して曜日を合わせます。
曜日を合わせればあとはstartからendの日付までループで回して日付のBoxを作成するだけです。
Boxの配置
display: ‘grid’,
でグリッドレイアウトにします。
gridTemplateColumns: ‘repeat(7, 1fr)’,
でBoxを横並びに均等に7つ表示して折り返してくれます。
もうこれだけでカレンダーの配置をしてくれます。
各Boxの高さの指定
aspectRatio: ‘1 / 1’
aspectRatioでアスペクト比で高さを指定できます。
1/1で縦幅(height)を横幅(width)と同じ幅にできます。
1/2で縦幅が横幅の2倍になります。
まとめ
Material-UIとReactでカレンダーとなっていますが、ほとんどmoment()とCSSのおかけです。
cssのグリッドレイアウト非常に便利です。
ただ、古いバージョンのブラウザに対応していない可能性もあるので対象の環境は要チェックです。