美文网首页
vue 日历选择组件

vue 日历选择组件

作者: 不知名的啦 | 来源:发表于2019-09-26 09:12 被阅读0次

    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。

    链接(😊😊😊😊😊😊😊😊😊😊😊😊😊😊😊😊)

    代码地址

    演示地址

    相关文章

      网友评论

          本文标题:vue 日历选择组件

          本文链接:https://www.haomeiwen.com/subject/vtnfuctx.html