LaravelとReactで作るSPAアプリ第3段です。
Reactで表示の根本となるカレンダーを表示していきましょう。
Laravel×ReactでつくるSPAスケジュールアプリ【③カレンダー表示】
カレンダーの概要を理解しよう
今回作成するカレンダーの完成形は以下の通りです。
この画像のスケジュールは次の対象ですが、カレンダーの全体図は上記のようなものです。
このカレンダーを目指して、まずはカレンダーそのものを不格好でも良いので作成してみましょう。
要件としては
- 実際に存在する形式のカレンダーが表示される
- ボタンクリックで前月、翌月へ移れる
- 月を移動した際に、その月のカレンダーが表示される
といったところですね。
弄るファイルは「resources/js/components/Example.js」です。
そこに以下の内容で貼り付けます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
import React,{Fragment,useState} from 'react'; import ReactDOM from 'react-dom'; function Example(){ const [year,setYear] = useState(new Date().getFullYear()) const [month,setMonth] = useState(new Date().getMonth()+1) const calendar = createCalendear(year,month) const onClick = n => () => { const nextMonth = month + n if (12 < nextMonth) { setMonth(1) setYear(year + 1) } else if (nextMonth < 1) { setMonth(12) setYear(year - 1) } else { setMonth(nextMonth) } } return ( <Fragment> <div className="calender-header"> <h1>{`${year}年${month}月`}</h1> <div className="calender-nav"> <button onClick={onClick(-1)}>{'<先月'}</button> <button onClick={onClick(1)}>{'翌月>'}</button> </div> </div> <table className="calender-table"> <thead> <tr> <th>日</th><th>月</th><th>火</th><th>水</th><th>木</th><th>金</th><th>土</th> </tr> </thead> <tbody> {calendar.map((week,i) => ( <tr key={week.join('')}> {week.map((day,j) => ( <td key={`${i}${j}`} id={day} > <div> <div> {day} </div> <div className="schedule-area"> </div> </div> </td> ))} </tr> ))} </tbody> </table> </Fragment> ); } function createCalendear(year,month){ const first = new Date(year,month - 1,1).getDay() return [0,1,2,3,4,5].map((weekIndex) => { return [0,1,2,3,4,5,6].map((dayIndex) => { const day = dayIndex + 1 + weekIndex * 7 return day - first }) }) } export default Example; if (document.getElementById('app')) { ReactDOM.render(<Example />, document.getElementById('app')); } |
1 2 3 |
const [year,setYear] = useState(new Date().getFullYear()) const [month,setMonth] = useState(new Date().getMonth()+1) const calendar = createCalendear(year,month) |
年度や月は翌月や前月の選択で変わるために、useState関数を使用しています。
getMonth関数は0からスタートするので、+1するのを忘れずに。
1 2 3 4 5 6 7 8 9 10 11 12 |
const onClick = n => () => { const nextMonth = month + n if (12 < nextMonth) { setMonth(1) setYear(year + 1) } else if (nextMonth < 1) { setMonth(12) setYear(year - 1) } else { setMonth(nextMonth) } } |
月を戻す処理も進める処理も同じなので、1つの関数ですね。
ただし13月になったら翌年の1月に、
0月になったら前年の12月に、といった処理を行っています。
また前述のカレンダー変数でyearとmonthにはステート変数を設定しています。
そのため、ボタンを押しただけで自動的に再度カレンダー関数が動き、
カレンダーの表示が変わるようになっています。
次のreturn内でカレンダーを表示しています。
ここでの説明は割愛しますが、次のカレンダー関数を理解すれば、この部分も理解できるはずです。
1 2 3 4 5 6 7 8 9 10 |
function createCalendear(year,month){ const first = new Date(year,month - 1,1).getDay() return [0,1,2,3,4,5].map((weekIndex) => { return [0,1,2,3,4,5,6].map((dayIndex) => { const day = dayIndex + 1 + weekIndex * 7 return day - first }) }) } |
カレンダー関数では、最初に月の初めの曜日を取得しています。
2021年12月なら水曜日といった形ですね。その形を元に、カレンダーを作成しています。
関数内部に2つの配列がありますね。1つめの5まで存在する配列は週を表しています。
さまざまな月のカレンダーを見ると分かりますが、カレンダーにおいて、週は最大で6週まで表示されます。
2つ目の配列は曜日に対応しています。7曜日あるので、7つの配列があります。
そしてその2つをmap関数で展開しつつreturnしています。
どういうことかというと、mapは配列の数字を0から順に処理します。
それゆえに最初の配列でははじめに0を、次に1を、そして2をといった順番で処理します。
そしてこの関数ではmap関数が2つ使われています。
それゆえに最初の配列の0を実行した後に、2つ目の配列の0を、次に2つ目の配列の1を、といった順で処理します。
戻り値はweekの値と、dayの値となっています。例えば2021年12月の場合は
- 0:[ー2、ー1、0、1、2、3、4]
- 1:[5、6、7、8、9、10、11]
- 2:[12、13、14、15、16、17、18]
- 3:[19、20、21、22、23、24、25]
- 4:[26、27、28、29、30、31、32]
- 5:[33、34、35、36、37、38、39]
といった形で返されます。縦の0~5までの数字がweekの値です。
その横の数字はdayで求めた値ですね。2021年12月の場合はfirstが水曜日(3)なので、3を引いて、最初が-2からスタートしています。
木曜日なら4を引くので、1の位置が変わることが分かります。
すでに帰ってくる値の段階でカレンダーの形をしていることが分かると思います。
あとはreturnの中でこの配列通りに表示してあげれば、カレンダー形式で表示ができます。
実際にこのコードで、表示は以下のようになります。
先月や翌月のボタンを押して、カレンダーが切り替わることを確認しておいてください。
カレンダーを調節しよう!
このままではカレンダーとして使えないので、調整します。
0以下の数値と、その月の最大値以上の数値を切り替えましょう。
上記の画像の場合、0以下の部分は11月の末日、31以降は1月の月初にしたいところです。
そのため、コードの一部を変更します。
1 2 3 4 5 6 7 8 9 10 |
const [year,setYear] = useState(new Date().getFullYear()) const [month,setMonth] = useState(new Date().getMonth()+1) const last = new Date(year,month,0).getDate() //追加 const prevlast = new Date(year,month-1,0).getDate() //追加 --省略-- <div> {day > last ? day - last : day <= 0 ? prevlast + day : day} </div> |
その部分を修正しています。前月の最終日、および当月の最終日のデータが欲しいので、それを先頭で取得しました。
lastは当月の最終日、prevlastは前月の最終日です。
day部分では3項演算子を用いています。
3項演算子はif文をJSXで使用できるようにしたものです。
以上のコードを適用させると、良い感じにカレンダーになります。
続いてデザインも適応していきましょう。
LaravelはデザインをSASSで指定できます。
「resources/sass」に「calender.scss」というファイルを新規作成し、以下のコードを書き込みます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
li{ list-style-type: none; font-size:0.8rem; } main{ width:80%; margin:0 auto; } .calender-header{ width:80%; display: flex; justify-content: space-between; margin:10px auto 1rem auto; h1{ font-size:2rem; } .calender-nav{ display: flex; justify-content: end; font-size:1.5rem; button{ border: none; background-color: transparent; margin-left:1rem; } } } .calender-table{ width:80%; margin:0 auto; text-align: left; thead{ text-align: center; th{ border: 1px solid silver; } } tbody tr{ td:hover{ background-color: silver; } td{ border:1px solid silver; padding:0.3rem 0.3rem 1rem 0.3rem; width:calc(100%/7); .nschedule-date{ text-align: right; font-size: 0.8rem; color:silver; } .schedule-date{ text-align: right; font-size: 0.8rem; } .schedule-area{ height:5rem; .schedule-title{ color:#fff; background-color: #3788D8; font-size: 0.8rem; border-radius: 3px; padding-left:0.2rem; margin-bottom:0.2rem; } } } td.today{ background-color: #f1efd6; } } } |
このSCSSファイルを読み込むように設定します。
設定する場所は同じ階層にある「app.scss」ファイルです。
以下の一文を追加します。
1 2 3 4 5 6 7 8 9 10 11 |
// Fonts @import url('https://fonts.googleapis.com/css?family=Nunito'); // Variables @import 'variables'; // Bootstrap @import '~bootstrap/scss/bootstrap'; // calender(original) @import 'calender'; //追加 |
ブラウザをリロードして、画面を確認してみましょう。
かなり良い感じのデザインになりましたね。
細かいところはお好みで変えても良いと思います。
今回はここまで。次回はスケジュールの表示を試してみましょう!
Laravel×Reactでつくるスケジュールアプリ | |
環境構築 | Git、Reactの導入 |
カレンダー表示 | スケジュール表示 |
スケジュール登録 | スケジュール更新 |
スケジュール削除 | 関数化Ⅰ |
関数化Ⅱ |