FullcalendarでtimeGridViewを使用するとデフォルトではscrollTimeによって6:00に自動的にスクロールされてしまいます。scrollTimeで値をセットしたとしても、別の位置にスクロールした後にprevボタンやbackボタンで表示範囲を切り替えると、スクロールした分は無視され、セットした位置で再度表示されてしまいます。
それらの不自由さを解決するために、All-Day Render Hooksを用いて以下の実装をします。
- 初回アクセス時は現在時刻までスクロール
- 表示範囲などの切り替え時には自動的にスクロールされないようにscrollTimeを無効化する
allDayDidMountで実装
- allDayDidMount内で初回は現在時刻にスクロール位置を取得
- scrollTime={false}でscrollTimeを無効化
import React, { useEffect, useState, createRef } from 'react';
import moment from 'moment';
import FullCalendar from '@fullcalendar/react';
import dayGridPlugin from '@fullcalendar/daygrid';
import timeGridPlugin from '@fullcalendar/timegrid';
import interactionPlugin from '@fullcalendar/interaction';
import '@fullcalendar/daygrid/main.css';
import '@fullcalendar/timegrid/main.css';
import '../css/custom_fullcalendar.css';
const week = const week = ['(日)', '(月)', '(火)', '(水)', '(木)', '(金)', '(土)']
// 現在時刻が何番目のslotに当たるか計算(単位はslotDurationで設定)
const nowSlotNumber = moment().hours()*4 + Math.floor(moment().minutes()/15) // 15分slot
const Calendar = (props) => {
const [events, setEvents] = useState(props.events)
const [scrollPosition, setScrollPosition] = useState(null)
const calendarRef = createRef()
const allDayDidMount = () => {
// それまでのスクロール位置を取得
let sp = document.querySelector('.fc-timegrid-slots').parentNode?.parentNode?.scrollTop
if(scrollPosition===null){ // 初回アクセス時は現在時刻にスクロール位置をセット
sp = 15*nowSlotNumber
// スクロール実行
setTimeout(() => document.querySelector('.fc-timegrid-slots').parentNode.parentNode.scrollTop = sp, 0)
}
setScrollPosition(sp) // 一応スクロール位置を保存
}
useEffect(()=>{
let calendarApi = calendarRef.current.getApi();
calendarApi.changeView(props.viewStyle, props.start.toDate())
setEvents(props.events)
// 月表示に切り替えた際にscroll位置を初期化
if (props.viewStyle==='dayGridMonth'){
setScrollPosition(null)
}
}, [props.viewStyle, props.events])
return (
<FullCalendar
ref={calendarRef}
plugins={[dayGridPlugin, timeGridPlugin, interactionPlugin]}
timezone={'Asia/Tokyo'}
views={{
timeGridWeek: {
dayHeaderFormat: function (date) {
return date.date.day+week[date.date.marker.getDay()]
}
},
timeGridDay: {
dayHeaderFormat: function (date) {
return date.date.day+week[date.date.marker.getDay()]
}
}
}}
slotLabelFormat={{
hour: 'numeric',
minute: '2-digit',
omitZeroMinute: false,
meridiem: 'short'
}}
locale={'ja'}
firstDay={1}
initialView={props.viewStyle}
initialDate={props.start.toDate()}
allDayText={''}
fixedWeekCount={false}
events={events}
nowIndicator={true}
scrollTime={false} // scrollTimeを無効にする
allDayDidMount={allDayDidMount} // scrollの設定をallDayDidMountで行う
timeFormat={'H:mm'}
slotDuration={'00:15'}
slotLabelInterval={'01:00'}
height={props.windowSize.height}
/>
)
}
コメント