vue平铺日历组件之按住ctrl、shift键实现跨月、跨年多选日期的功能

已经好久没有更新过博客了,大概有两三年了吧,因为换了工作,工作也比较忙,所以也就没有时间来写技术博客,期间也一直想写,但自己又比较懒,就给耽误了。今天这篇先续上,下一篇什么时候写,我也不知道,随心所欲、随遇而安、安之若素、素不相识也就无所谓了吧。

一开始看到这个功能需求,我也很懵逼,因为从来没有做过啊,哈哈。。。但转念一想既然产品能提出这个需求,想必会有人实现过,就去网上查了查资料,果不其然,还真有人做过,但离我想要的效果还是差着十万八千里,所以按照网上大神的思路,结合我司的实际需求,自己就把它给捣鼓出来了。

其实刚做好的效果还是能实现产品的需求的,我就让同事帮忙测试一下看看有没有什么bug,因为我司对bug的要求以及对用户体验的要求还是很严格的,所以在同事的实际测试以及提醒下,后面我又参照电脑上基于ctrl、shift键来选中文件的实际效果做了改进,算是不给测试提bug的机会吧。

照旧先上两张最后实现的效果图:

vue平铺日历组件之按住ctrl、shift键实现跨月、跨年多选日期的功能插图
vue平铺日历组件之按住ctrl、shift键实现跨月、跨年多选日期的功能插图1

先来看看实现单月的日期组件calendar.vue






从以上也能看出,我们的需求还是很复杂的,比如,历史日期也就是所谓的过期的日期不能被选中,周六周日的日期要标红,还可以把工作日置为休息日,休息日置为工作日等等。这些功能说起来就一句话,可要实现出来,那可就属实太复杂了。

对了,在实现的过程中,我还使用到了vuex来保存点击选中的数据calendar.js:

let selectList = []
let shiftData = null
let shiftDate = ''
let currentSelect = []
let lastSelect = []

// 获取两个日期中间的所有日期
const getBetweenDay = (starDay, endDay) => {
  var arr = []
  var dates = []

  // 设置两个日期UTC时间
  var db = new Date(starDay)
  var de = new Date(endDay)

  // 获取两个日期GTM时间
  var s = db.getTime() - 24 * 60 * 60 * 1000
  var d = de.getTime() - 24 * 60 * 60 * 1000

  // 获取到两个日期之间的每一天的毫秒数
  for (var i = s; i = 10 ? (time.getMonth() + 1) : ('0' + (time.getMonth() + 1))
    var day = time.getDate() >= 10 ? time.getDate() : ('0' + time.getDate())
    var YYMMDD = year + '' + mouth + '' + day
    dates.push(YYMMDD)
  }

  return dates
}

const shiftSelect = (dateStr, item) => {
  if (!shiftData) {
    shiftData = item.date
    shiftDate = ${item.year}-${item.month}-${item.day}
    // 如果当前日期已选中,再次点击当前日期就取消选中。
    if (selectList.includes(dateStr)) {
      selectList.splice(selectList.indexOf(dateStr), 1)
    } else {
      selectList.push(dateStr)
    }
  } else {
    if (shiftData  item.date) {
      currentSelect = getBetweenDay(${item.year}-${item.month}-${item.day}, shiftDate)
    } else {
      currentSelect = [dateStr]
    }

    selectList = selectList.filter(item => !lastSelect.includes(item)) // 移除上次按shift复制的
    selectList = selectList.concat(currentSelect) // 添加本次按shift复制的
    lastSelect = currentSelect
  }
}

export default {
  namespaced: true,
  state: {
    selectList: []
  },
  mutations: {
    setSelectCalendar (s, { dateStr, item, isCtrl, isShift }) {
      // 按住ctrl
      if (isCtrl && !isShift) {
        // 如果当前日期已选中,再次点击当前日期就取消选中。
        if (selectList.includes(dateStr)) {
          selectList.splice(selectList.indexOf(dateStr), 1)
        } else {
          selectList.push(dateStr)
        }

      // 加上lastSelect = []这个就会在shift连续选了多个后,再按住ctrl键取消已选中的日期的中间的几个后,下次再按住
      // shift多选时,就会从按住ctrl取消选中的最后一个日期开始连续选择,但刚才取消已选中的那些日期
      // 之前的已经选中的日期依旧处于选中状态,与电脑自身的按住shift键多选的效果略有不同,所以要注释掉这串代码。
      // lastSelect = []  // 最开始这串代码是放开的
      } else if (isShift && !isCtrl) {
        // 加上selectList = []可以实现按住ctrl单选几个不连续的日期后,再按住shift键连选其他日期,就可以把之前
        // 按住ctrl键单选的其他日期都取消选中。不加selectList = []是可以在按住shift键连选其他日期时同时保留之前
        // 按住ctrl键单选的其他日期。
        selectList = [] // 最开始这串代码是没有的

        shiftSelect(dateStr, item)
      } else if (isCtrl && isShift) { // 同时按住ctrl和shift
        lastSelect = []
        shiftSelect(dateStr, item)
      } else { // 不按ctrl和shift,一次只能选择一个
        selectList = [dateStr]
      }

      if (!isShift) {
        shiftData = item.date
        shiftDate = ${item.year}-${item.month}-${item.day}
      }

      selectList = [...new Set(selectList)].sort() // 去重、排序

      s.selectList = selectList
    },
    setSelectEmpty (s) {
      selectList = []
      shiftData = null
      shiftDate = ''
      currentSelect = []
      lastSelect = []
      s.selectList = []
    }
  }
}

再来看看在以上单个日期组件的基础上实现1年12个月日历平铺的代码吧:






写到这里就不准备再往下写了,所有的代码都贴出来了。如果你想要的效果跟我的这个不太一样,你自己在这个基础上改吧改吧应该就可以用了。其实最关键的部分也就是那个按住ctrl、shift键实现跨月、跨年多选日期,理解了这个原理,其余的实现部分尽管复杂但并不难。

文章来源于互联网:vue平铺日历组件之按住ctrl、shift键实现跨月、跨年多选日期的功能

THE END
分享
二维码