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

jQuery日历显示异常及日期状态类错误赋值问题求助

jQuery日历显示异常及日期状态类错误赋值问题求助

嗨,看你卡这个问题三周了,太闹心了!我帮你梳理下代码里的几个核心问题,这些应该就是导致各种诡异BUG的根源:

1. 最致命的异步执行顺序错误

你现在的代码里,生成calendarAvailabilities的for循环和getOpenDays(cal)调用是在AJAX请求的回调函数外面!AJAX是异步操作——浏览器发起请求后不会等它返回,直接就去执行后面的代码了。这时候回调里的DOM修改(加/减fc-closedDay类)根本还没跑,你用的还是之前的旧DOM状态,这就导致日历数据总是错位,切换月份时混合新旧数据。

修复方法:把for循环和getOpenDays(cal)完全移到AJAX的回调函数内部,确保只有当数据返回、DOM状态更新完成后,才去生成日历数据。

2. DOM选择器的模糊匹配问题

你用contains('" + d + "')匹配日期时,比如d=5,页面上所有包含"5"的日期(15、25、5号)都会被命中,直接导致错误的日期被加上/移除fc-closedDay类——这就是为什么有时候所有div都被标成闭店的原因。另外,法语(Lun/Mar)和英语(Mon/Tue)的星期标签混用,也可能导致选择器匹配异常。

修复方法:

  • 优先给每个日期div加精确的data-date属性(比如data-date="2024-05-05"),用属性选择器精确匹配;
  • 如果没法改DOM结构,就用filter做精确文本匹配:
    // 精确匹配日期数字,而非包含
    jQuery("span.fc-date").filter(function() {
      return $(this).text().trim() === d.toString();
    })
    

3. 月份索引的日期处理错误

JavaScript的Date对象月份是从0开始的(0=1月,11=12月),你直接用cal.getMonth()转成两位数字生成日期字符串,会导致月份整体偏移一个月(比如cal.getMonth()返回0,转成"01"实际对应二月),这会让calendarAvailabilities的键完全错误,日历自然显示不对。

修复方法:生成日期时给月份加1,修正索引偏移:

const actualMonth = cal.getMonth() + 1; // 转成1-12的实际月份
const formattedMonth = number.format(actualMonth);

4. 未清除旧的状态类

切换月份时,上一个月份的fc-closedDay类没有被清除,新的类直接叠加,导致DOM状态混乱,混合了多个月份的闭店数据。

修复方法:在AJAX回调开始时,先清除所有日期div的旧状态:

function(data) {
  // 先清空旧的闭店标记
  jQuery("div.fc-closedDay").removeClass('fc-closedDay');
  // 再处理新数据...
}

修正后的核心代码示例

function getClosingDays(cal) {
  // 获取闭店日期
  jQuery.get( 
    "index.php?option=com_skydivespa&task=reservation.getClosingDays", 
    {"month": cal.getMonth(), "year": cal.getYear()},
    function(data) {
      console.log(data);
      const periods = JSON.parse(data);
      
      // 第一步:清除所有旧的闭店状态
      jQuery("div.fc-closedDay").removeClass('fc-closedDay');

      if (periods['data'].length === 1) {
        // 处理单周期情况,用映射优化代码
        const weekdayMap = {
          mon: "Lun", tue: "Mar", wed: "Mer", thu: "Jeu", fri: "Ven", sat: "Sam", sun: "Dim"
        };
        Object.entries(weekdayMap).forEach(([key, label]) => {
          if (periods['data'][0][key] === 0) {
            jQuery("span.fc-weekday").filter(function() {
              return $(this).text().trim() === label;
            }).parent("div").addClass('fc-closedDay');
          }
        });
      } else {
        // 处理多周期情况
        for (let i = 0; i < periods.data.length; i++) {
          const dateStartPeriod = new Date(periods['data'][i].date_start);
          const dateEndPeriod = new Date(periods['data'][i].date_end);
          const weekdayMap = {
            mon: "Mon", tue: "Tue", wed: "Wed", thu: "Thu", fri: "Fri", sat: "Sat", sun: "Sun"
          };

          Object.entries(weekdayMap).forEach(([key, label]) => {
            const isClosed = periods['data'][i][key] === 0;
            // 遍历周期内的每一天
            for (let d = dateStartPeriod.getDate(); d <= dateEndPeriod.getDate(); d++) {
              // 精确匹配日期+星期的组合
              const dateEl = jQuery("span.fc-date").filter(function() {
                return $(this).text().trim() === d.toString();
              }).next("span.fc-weekday").filter(function() {
                return $(this).text().trim() === label;
              }).parent("div");
              
              isClosed ? dateEl.addClass('fc-closedDay') : dateEl.removeClass('fc-closedDay');
            }
          });
        }
      }

      // 生成日历可用数据(确保DOM已更新)
      const calendarAvailabilities = {};
      const numberFormatter = Intl.NumberFormat('en-US', {minimumIntegerDigits: 2});
      const year = cal.getYear();
      const formattedMonth = numberFormatter.format(cal.getMonth() + 1); // 修正月份索引

      for (let d = 1; d <= 31; d++) {
        const formattedDay = numberFormatter.format(d);
        const dateKey = `${formattedMonth}-${formattedDay}-${year}`;
        const dateEl = jQuery("span.fc-date").filter(function() {
          return $(this).text().trim() === formattedDay;
        }).parent("div");

        calendarAvailabilities[dateKey] = dateEl.hasClass('fc-closedDay')
          ? ['<span class="close uk-button uk-button-small uk-button-primary uk-margin-small">Close</span>']
          : ['<span class="free uk-button uk-button-small uk-button-primary uk-margin-small" onclick="validateResaStep1(\'9:00\')" slot="9:00:00">9:00-10:00</span>'];
      }

      // 更新日历数据
      cal.setData(calendarAvailabilities);
      // 在DOM更新后调用getOpenDays
      getOpenDays(cal);
    }
  );
}

额外优化:用Async/Await简化异步逻辑

如果想避免回调嵌套,还可以把jQuery的AJAX转成Promise用async/await:

async function getClosingDays(cal) {
  try {
    // 转成Promise,用await等待请求返回
    const data = await jQuery.get(
      "index.php?option=com_skydivespa&task=reservation.getClosingDays", 
      {"month": cal.getMonth(), "year": cal.getYear()}
    ).promise();
    
    // 后面的处理逻辑和上面一致
  } catch (err) {
    console.error("获取闭店日期失败:", err);
  }
}

备注:内容来源于stack exchange,提问作者Sephirah

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.22 07:18:12