You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在flatpickr中异步显示入住状态且不造成服务器请求过载

嘿,这个需求我之前也做过,刚好可以给你分享一套靠谱的实现方案——既能用flatpickr的onDayCreate钩子渲染入住标记,又能通过缓存和防抖避免服务器请求过载,咱们一步步来:

核心思路

要避免请求过载,关键要做到三点:

  • 缓存已加载的月份数据:同一个月份只请求一次,后续切换回来直接用缓存
  • 按需+防抖请求:只有用户切换到未加载过的月份才发起请求,且快速切换时延迟请求,避免短时间内多次调用API
  • 异步渲染兼容:数据加载完成后触发日历重绘,确保标记能正确显示到对应日期单元格上
完整实现代码

1. HTML 基础结构

先引入flatpickr的样式和脚本,再准备日历容器:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
<style>
  /* 自定义入住标记的样式 */
  .booking-mark {
    width: 6px;
    height: 6px;
    background-color: #2563eb; /* 蓝色标记,可按需修改 */
    border-radius: 50%;
    display: block;
    margin: 0 auto;
    margin-top: 2px; /* 避免和日期数字重叠 */
  }
</style>
<div id="calendar"></div>
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>

2. JavaScript 逻辑实现

这里包含了缓存、异步请求、日历初始化和标记渲染的完整逻辑:

// 缓存已加载的月份入住数据,键为「YYYY-MM」格式的字符串
const bookingCache = {};
// 记录正在请求的月份,避免重复请求
const loadingMonths = new Set();
// 防抖定时器,避免快速切换月份时发起过多请求
let debounceTimer;

// 初始化flatpickr月视图日历
const fp = flatpickr("#calendar", {
  inline: true, // 渲染为内嵌式月视图日历
  dateFormat: "Y-m-d", // 统一日期格式为YYYY-MM-DD
  disableMobile: true, // 禁用移动端原生日期选择器(可选)

  // 日历初始化完成时,加载当前月份的入住数据
  onReady: function(selectedDates, dateStr, instance) {
    loadMonthBookings(instance.currentYear, instance.currentMonth + 1, instance);
  },

  // 用户切换月份时触发,加载对应月份的入住数据
  onMonthChange: function(selectedDates, dateStr, instance) {
    // 防抖处理:300ms内多次切换只发起最后一次请求
    clearTimeout(debounceTimer);
    debounceTimer = setTimeout(() => {
      loadMonthBookings(instance.currentYear, instance.currentMonth + 1, instance);
    }, 300);
  },

  // 每个日期单元格创建时,渲染入住标记
  onDayCreate: function(dObj, dStr, fp, dayElem) {
    // 获取当前日期所属的月份(YYYY-MM)
    const dateMonth = dStr.substring(0, 7);
    // 如果缓存中有该月数据,检查当前日期是否有入住
    if (bookingCache[dateMonth] && bookingCache[dateMonth].includes(dStr)) {
      // 添加入住标记元素
      dayElem.innerHTML += "<span class='booking-mark'></span>";
    }
  }
});

/**
 * 加载指定月份的入住数据
 * @param {number} year 年份
 * @param {number} month 月份(1-12)
 * @param {object} fp flatpickr实例
 */
function loadMonthBookings(year, month, fp) {
  const monthKey = `${year}-${String(month).padStart(2, "0")}`;
  // 如果缓存已有数据或正在请求,直接返回
  if (bookingCache[monthKey] || loadingMonths.has(monthKey)) return;

  // 标记该月份正在请求
  loadingMonths.add(monthKey);
  // 发起异步请求,替换成你的后端API地址
  fetch(`/api/bookings?month=${monthKey}`)
    .then(res => {
      if (!res.ok) throw new Error("请求失败");
      return res.json();
    })
    .then(data => {
      // 假设返回的数据是该月有入住的日期数组,例如["2024-05-01", "2024-05-03"]
      bookingCache[monthKey] = data;
      // 重绘日历,触发onDayCreate更新所有日期标记
      fp.redraw();
    })
    .catch(err => {
      console.error("加载入住数据失败:", err);
    })
    .finally(() => {
      // 移除请求中的标记
      loadingMonths.delete(monthKey);
    });
}
关键优化点
  1. 防抖处理:用户快速切换月份时,延迟300ms发起请求,避免短时间内多次调用API
  2. 重复请求拦截:用loadingMonths集合记录正在请求的月份,防止同一个月份被多次请求
  3. 缓存复用:已加载过的月份数据存在bookingCache中,切换回来直接使用,无需再次请求
  4. 异步渲染兼容:请求完成后调用fp.redraw()触发日历重绘,确保异步加载的数据能正确渲染标记
注意事项
  • 后端API需要接收month参数(格式为YYYY-MM),返回该月所有有入住的日期数组
  • 可以根据需求调整booking-mark的样式,比如颜色、大小、位置
  • 如果需要支持多月份视图(比如同时显示3个月),只需要在onMonthChange和onReady中处理当前显示的所有月份即可

内容的提问来源于stack exchange,提问作者stUrb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:01:17