vue 日历选择组件

vue 日历选择组件

日历作为手机端一个常用的控件,想必大家多多少少都会用到,现在github上有很多优秀的日历控件,但可能有些时候并不能满足我们日常的业务开发需求,话不多说,下面简单实现一个日历的选择功能!

链接和图片展示

图片示例
(●’◡’●) (●’◡’●)(●’◡’●)(●’◡’●)(●’◡’●)(●’◡’●)演示示例链接

核心代码分析

首先,我们明确一点,日历,就是时间的选择,有了时间对应的数据,就解决了绝大部分问题,简单分析下,无非就是对应12个月份,然后每个月份对应有几个星期,下面代码实现下,首先创造月份数据(下面代码部分日期方法封装在utils中,完整代码里面有):

buildData() {
    let startDate = new Date();
    let endDate = new Date().addMonths(12); // 月份加12
    let dateData = [];
    while (startDate <= endDate) {
      let month = [];
      dateData.push(month);
      startDate.addMonths(1);
    }
    return dateData;
  },   

现在对应的月份数据已经有了,当然都是空数组,没什么用,下面我们再来创造对应月份的数据,分析下,每月的具体日期是从1号开始,然后让他循环加1天,只要判断的他的月份等于这个月就证明他是这个月的日期,同时周一到周日怎么跟我们的日期一一对应呢?在这里,我们明确一个问题,本文日历对应月份只展示该月中的数据(也就是1号到最后一天),不是该月的数据为“”。明确了之后就容易了,首先我们知道日期getDay()这个方法是可以取得对应周几的(注意:周日该方法返回的是0),这样我们先判断该月的1号是周几?这样第一周的数据(跟周几一一对应)就可以出来了,

new Array(time.getDay() === 0 ? 6 : time.getDay() - 1).fill('')

(不是该月份的值为空),该月的1号对应周几确定了后,下面对应日期加1循环判断就可以了, 还有一个问题,就是该月的最后一天结束后加入对应该周的数据不满足7天,我们要补充完整。
下面是完整代码:

  // 创建日期月份数据
  buildMonthDate(time) {
    let monthDate = [];
    let month = time.getMonth();
    let date = new Date(time);
    var t = time.getDay() === 0 ? 6 : time.getDay() - 1;
    let dateList = new Array(t).fill('');

    while (date.getMonth() === month) {
      let dateInfo = {};
      if (dateList.length === 7) {
        monthDate.push(dateList);
        dateList = [];
      }
      dateInfo = {
        date: date.format('yyyy/MM/dd'),
      }
      dateList.push(dateInfo);
      date.addDays(1);
    }

    // 不满7 补充完整
    if (dateList.length) {
      for (let i = dateList.length; i < 7; i++) {
        dateList.push('');
      }
      monthDate.push(dateList);
      dateList = null;
    }
    return {
      month: monthDate,
      title: `${time.getFullYear()}年${time.getMonth() + 1}月`,
      monthId: `${time.getFullYear()}${time.getMonth() + 1}`
    };
  },

现在对应的数据已经有了,剩下就是画下对应的页面,这个本文就不做详细介绍了,感兴趣的话可以看详细代码(末尾有地址)。

其他功能完善

下面我们来完善下其他功能,增加节假日、加班日、日期范围限制不可选等,我们完善下代码如下:

 // 创建日期月份数据
    buildMonthDate(time) {
      let monthDate = [];
      let month = time.getMonth();
      let date = new Date(time);
      var t = time.getDay() === 0 ? 6 : time.getDay() - 1;
      let dateList = new Array(t).fill('');

      while (date.getMonth() === month) {
        let dateInfo = {};
        if (dateList.length === 7) {
          monthDate.push(dateList);
          dateList = [];
        }
        dateInfo = {
          text: date.getDate(),
          dateTime: date.getTime(),
          date: date.format('yyyy/MM/dd'),
          tips: ''
        }
        // 开始日期之前和结束日期之后的日期置灰
        if (date < this.startDate || date > this.endDate) {
          dateInfo.disable = true;
        }
        if (this.mode === 'end' && new Date(date) < new Date(this.checkStart)) {
          // 返程时间必须大于去程时间
          dateInfo.disable = true;
        }

        // 节日处理
        let festival = getFestival(date);
        if (festival) {
          dateInfo.festival = festival;
          dateInfo.text = festival;
        }
        if (getHolidays(dateInfo.date)) {
          // 休息日
          dateInfo.relax = true;
          dateInfo.tips = '休';
        } else if (getWorks(dateInfo.date)) {
          // 工作日
          dateInfo.fillWork = true;
          dateInfo.tips = '班';
        }
        // 最近日期处理  今天明天 后天
        let recentDay = getRecentDay(date);
        if (recentDay) {
          dateInfo.alias = recentDay;
          dateInfo.festival = '';
        }

        dateList.push(dateInfo);
        date.addDays(1);
      }

      // 不满7 补充完整
      if (dateList.length) {
        for (let i = dateList.length; i < 7; i++) {
          dateList.push('');
        }
        monthDate.push(dateList);
        dateList = null;
      }
      return {
        month: monthDate,
        title: `${time.getFullYear()}年${time.getMonth() + 1}月`,
        monthId: `${time.getFullYear()}${time.getMonth() + 1}`
      };
    },
点击选择功能

下面我们来处理下选择日期后的事件,明确下我们支持的几种模式

  • 选择开始模式
  • 选择结束模式
  • 选择范围

分析下对应功能

  • 选择开始时间的话没有特殊处理
  • 选择结束模式的话要确保只能选择开始时间之后的时间
  • 选择范围模式的话,支持点击两次,第一次选择开始时间,第二次选择结束时间(第二次点击需要判断,如果第二次点击小于第一次点击的时间,认为是新的第一次点击)

下面代码实现:

    // 点击事件处理    
    clickHandler(e) {
      if (e.currentTarget.dataset.disabled) return;
      let date = e.currentTarget.dataset.date;
      let t = {
        'start': 'clickHandlerStart',
        'end': 'clickHandlerEnd',
        'range': 'clickHandlerRange'
      }
      
      this.selected = new Date(date);
      let emitData = this[t[this.mode]](date);
      if (!emitData) return;
      
      this.selecteFuc && this.selecteFuc({
          date,
          BE: emitData
      });
    },
    clickHandlerStart(date) {
      this.checkStart = date;
      if (compare(date) >= compare(this.checkEnd)) {
        this.checkEnd = '';
      }
      alert(`选择开始时间为${date},结束时间为${this.checkEnd || '--'}`);
      return [date, this.checkEnd];
    },
    clickHandlerEnd(date) {
      this.checkEnd = date;
      alert(`选择开始时间为${this.checkStart || '--'},结束时间为${date || '--'}`);
      return [this.checkStart, date];
    },
    clickHandlerRange(date) {
      if (!this.twoClick) {
        this.checkStart = date;
        this.checkEnd = '';
      } else {
        // 点击比较 第二次点击值需要大于第一次点击值
        if (compare(date) < compare(this.checkStart)) {
          this.twoClick = 0;
          this.checkStart = date;
        } else {
          this.checkEnd = date;
        }
      }
      ++this.twoClick;
      if (this.twoClick === 1) return false;
      this.twoClick = 0;
      alert(`选择开始时间为${this.checkStart || '--'},结束时间为${this.checkEnd || '--'}`);
      return [this.checkStart, this.checkEnd];
    }

以上就是对应功能实现过程,欢迎大家issue。

链接(????????????????)

代码地址

演示地址

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值