Flatpickr选择日期后重绘丢失onDayCreate修改,如何重新触发处理?
问题
我用Vue.js写了一个自定义日历组件,基于Flatpickr实现,能给不同日期设置不同背景色。但选择任意日期后,所有自定义样式都会丢失——因为Flatpickr会重绘日期DOM元素。我试过Flatpickr文档里的多个事件钩子,但它们都没法像onDayCreate那样直接操作日期元素。请问怎么在日期网格更新时,重复执行onDayCreate回调里的样式设置逻辑?
组件代码
<script> import { UI_DATE_FORMAT } from "../data/System"; import flatPickr from "vue-flatpickr-component"; import RequestService from "../services/RequestService"; const request = new RequestService(); export default { props: [], data() { return { selectedDate: "", currentMonth: null, busyDaysData: {}, updateDataProcess: false, dateConfig: { inline: true, dateFormat: UI_DATE_FORMAT, monthSelectorType: "static", wrap: false, onDayCreate: function (dObj, dStr, fp, dayElem) { this.calendarDayCreate(dayElem, fp); }.bind(this), }, }; }, components: { flatPickr, }, mounted() {}, methods: { calendarDayCreate(dayElem, fp) { const month = fp.currentMonth + 1; const dayDay = dayElem.dateObj.getDate(); const dayMonth = dayElem.dateObj.getMonth() + 1; if (dayMonth !== month) return; if (this.updateDataProcess) { const timer = setTimeout(() => { if (!this.updateDataProcess) { clearTimeout(timer); this.handleDay(dayDay, dayElem); } }, 250); } else { if (this.currentMonth !== month) { this.updateDataProcess = true; new Promise((onSuccess, onError) => { request.requestData( { data: "Calendar\\BusyDaysForMonth", arguments: { appointment_id: 0, month, extended: true, }, }, (response) => { onSuccess(response); }, (error) => { onError(error); } ); }).then( (response) => { this.updateDataProcess = false; this.currentMonth = month; this.busyDaysData = response.data; this.handleDay(dayDay, dayElem); }, (error) => { this.updateDataProcess = false; console.log(error); } ); } } }, handleDay(day, dayElem) { if (!this.busyDaysData[day]) return; console.log(dayElem); dayElem.classList.add( "app-" + this.busyDaysData[day].appointment_status ?? "" ); }, }, }; </script> <template> <b-row id="appointments-calendar"> <b-col cols="12"> <flat-pickr :config="dateConfig" v-model="selectedDate" class="form-control flatpickr active" :placeholder="$t('appointments_input_date_ph')" > </flat-pickr> </b-col> </b-row> </template> <style scoped lang="scss"></style>
问题图示


解决方案
Flatpickr在日期选择、月份切换等操作时会完全重绘日期网格,onDayCreate仅在初始创建日期元素时触发,所以需要在网格更新后重新执行样式设置逻辑。以下是两种可行方案:
方案一:监听网格更新事件,批量重设样式
在dateConfig中添加onMonthChange(月份切换时触发)和onValueChange(日期选择时触发)两个钩子,每次触发时遍历当前所有日期元素,重新应用样式:
- 修改
dateConfig:
dateConfig: { inline: true, dateFormat: UI_DATE_FORMAT, monthSelectorType: "static", wrap: false, onDayCreate: function (dObj, dStr, fp, dayElem) { this.calendarDayCreate(dayElem, fp); }.bind(this), // 添加这两个事件钩子 onMonthChange: function(selectedDates, dateStr, fp) { this.reapplyDayStyles(fp); }.bind(this), onValueChange: function(selectedDates, dateStr, fp) { this.reapplyDayStyles(fp); }.bind(this) },
- 新增
reapplyDayStyles方法:
methods: { // ... 原有方法 reapplyDayStyles(fp) { // 获取当前日历容器内的所有日期元素 const dayElements = fp.calendarContainer.querySelectorAll('.flatpickr-day'); const currentMonth = fp.currentMonth + 1; dayElements.forEach(dayElem => { const dateObj = dayElem.dateObj; const dayMonth = dateObj.getMonth() + 1; // 只处理当前月份的日期 if (dayMonth !== currentMonth) return; const day = dateObj.getDate(); // 先清除之前的自定义类,避免重复叠加 const existingAppClasses = Array.from(dayElem.classList).filter(cls => cls.startsWith('app-')); if (existingAppClasses.length) { dayElem.classList.remove(...existingAppClasses); } // 重新应用样式 this.handleDay(day, dayElem); }); } }
方案二:优化数据加载后的样式覆盖
原代码中calendarDayCreate是逐个处理日期元素,切换月份时可能只处理了部分元素。可以在数据加载完成后,直接遍历当前月份的所有日期元素,统一应用样式:
修改calendarDayCreate中的Promise成功回调:
.then( (response) => { this.updateDataProcess = false; this.currentMonth = month; this.busyDaysData = response.data; // 数据加载完成后,遍历当前月份所有日期元素 const dayElements = fp.calendarContainer.querySelectorAll('.flatpickr-day'); dayElements.forEach(dayElem => { const dateObj = dayElem.dateObj; const dayMonth = dateObj.getMonth() + 1; if (dayMonth !== month) return; const day = dateObj.getDate(); this.handleDay(day, dayElem); }); }, (error) => { this.updateDataProcess = false; console.log(error); } )
注意事项
- 两种方案可以结合使用:方案一处理日期选择、月份切换后的重绘,方案二确保月份切换时数据加载完成后所有日期都能应用样式。
- 重设样式前清除原有自定义类,避免样式冲突或重复添加。
内容的提问来源于stack exchange,提问作者Михаил Хоменко
相关产品推荐
相关产品推荐

