记录–设计一个可选择不连续的时间范围的日期选择器

  • 记录–设计一个可选择不连续的时间范围的日期选择器已关闭评论
  • 179 次浏览
  • A+
所属分类:Web前端
摘要

普通的时间选择器要么只能单选,要么只能选范围,不可以随意选择若干个时间,同时大多数现成的时间选择器选择结束会收起来,很不方便。现在需求如下 1、可以自己控制展开收起 2、可以选择不连续的多个时间范围的日期 3、可以批量选中日期,不需要一个个点击


这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

记录--设计一个可选择不连续的时间范围的日期选择器

  • npm包:sta-datepicker
  • 效果图 

记录--设计一个可选择不连续的时间范围的日期选择器

需求

普通的时间选择器要么只能单选,要么只能选范围,不可以随意选择若干个时间,同时大多数现成的时间选择器选择结束会收起来,很不方便。现在需求如下 1、可以自己控制展开收起 2、可以选择不连续的多个时间范围的日期 3、可以批量选中日期,不需要一个个点击

实现过程(分几个步骤,具体可以看源码)

1、生成一个日历

  • 顶部为固定的几个按钮,可以绑定切换年份月份的函数

  • 中间为固定的星期,一个七个

  • 底部为具体日期,由三部分组成,即:上个月底几天,这个月整个月,下个月初几天

    • 算好平年闰年,输出当前月份第一天是周几
    • 根据当前月份的第一天的星期数,计算日历要展示上个月月底的几天
    • 根据当前月份最后一天的星期数,计算日历要展示下个月月初的几天
  • 日期部分使用div遍历三个数组,左浮动或者弹性盒直接堆起来即可

  created() {     this.trueDateBox()   },   methods: {     trueDateBox() {       if (this.date === "") {         const date = new Date()         this.year = date.getFullYear()         this.updateLeapYear()         this.month = date.getMonth() + 1         this.day = null       }       this.dayScreen()     },     // 设置算好闰年平年     updateLeapYear() {       if (this.isLeapYear(this.year)) {         this.monthDay[1] = 29       } else {         this.monthDay[1] = 28       }     },     isLeapYear(year) {       return year % 100 === 0 ? year % 400 === 0 : year % 4 === 0     },     // 日期显示     dayScreen() {       // 渲染上个月,第一行       const firstDate = new Date(this.year, this.month - 1, 1)       const firstWeek = firstDate.getDay()       let preMonthDay = null       if (this.month === 1) {         preMonthDay = this.monthDay[11]       } else {         preMonthDay = this.monthDay[this.month - 2]       }       console.log("preMonthDay", this.monthDay[11], this.month)        for (let i = 0; i < preMonthDay; i++) {         this.previousMonth[i] = i + 1       }       if (firstWeek === 0) {         this.previousMonth = this.previousMonth.slice(-7)       } else {         this.previousMonth = this.previousMonth.slice(-firstWeek)         console.log(33, this.previousMonth)       }        // 渲染下个月, 最后一行       const endDate = new Date(         this.year,         this.month - 1,         this.monthDay[this.month - 1]       )       const endWeek = endDate.getDay()       let nextMonthDay = null       if (this.month === 12) {         nextMonthDay = this.monthDay[0]       } else {         nextMonthDay = this.monthDay[this.month]       }       for (let i = 0; i < nextMonthDay; i++) {         this.nextMonth[i] = i + 1       }       if (endWeek === 6) {         this.nextMonth = this.nextMonth.slice(0, 7)       } else {         this.nextMonth = this.nextMonth.slice(0, 6 - endWeek)       }     },   }

2、绑定四个固定的函数

  • 点击上一年,下一年,上个月,下个月时,需要计算跨年的情况
    // 年份的增减     addYear() {       this.year++       this.updateLeapYear()     },     reduceYear() {       this.year--       this.updateLeapYear()     },     // 月份的增减     addMonth() {       this.month++       if (this.month > 12) {         this.month = 1         this.addYear()       }     },     reduceMonth() {       this.month--       if (this.month < 1) {         this.month = 12         this.reduceYear()       }     },

3、点击具体日期时,确定状态

  • 使用数组存起当前已选的日期,使用一个变量记录当前半选的日期
  • 通过一个函数isActive给每个日期绑定类名,从而在视图上显示出来,同时可以确定状态的切换
    • 如果点击了已选日期的数据,需要剔除,改为空白状态
    • 如果点击了半选态日期,则直接选中当前日期,变为已选日期
    • 如果点击了空白状态日期,则可能有两种情况,一是已存在半选态日期,等待闭合,而是不存在半选态日期,当前设置为半选
methods: {     // 突出显示当前日期     isActive(index) {       const date = new Date()       const y = date.getFullYear()       const m = date.getMonth() + 1       const d = date.getDate()       const obj = {}        if (this.year === y && this.month === m && index === d) {         obj.today = true       }       const newIndexStr = index < 10 ? `0${index}` : `${index}`       const newMonthStr = this.month < 10 ? `0${this.month}` : `${this.month}`       const item = `${this.year}/${newMonthStr}/${newIndexStr}`       if (item === this.partialSelect) {         obj.active = true       }       if (this.selctDate.includes(item)) {         obj.activeRange = true       }       return obj     },     selectDay(e, type) {       const iText = e.target.innerText       const sDate = Number(iText) < 10 ? `0${iText}` : `${iText}`       if (type === "previousMonth") {         if (this.month === 1) {           this.month = 12           this.reduceYear()         } else {           this.month = this.month - 1         }       } else if (type === "nextMonth") {         if (this.month === 12) {           this.month = 1           this.addYear()         } else {           this.month = this.month + 1         }       }        let arr = this.selctDate.map((i) => new Date(i).getTime())       const newMonthStr = this.month < 10 ? `0${this.month}` : `${this.month}`       const curSelectTime = `${this.year}/${newMonthStr}/${sDate}`       const curSelectTimeStamp = new Date(curSelectTime).getTime()       const clsName = e.target.className // 通过类名判断当前是什么状态       if (clsName.includes("activeRange")) {         // 点击了范围内的数据,需要剔除         arr = arr.filter((i) => i !== curSelectTimeStamp)       } else if (clsName.includes("active") && !clsName.includes("activeRange")) {         // 点击了一个半选状态的日期,准备扩展范围或者单选一个         if (this.selctDate.length) {           const itemTime = arr[0]           const itemTime2 = arr[arr.length - 1]           const selectTime = curSelectTimeStamp           if (selectTime < itemTime) {             console.log("点击了范围之前的时间")           } else if (selectTime > itemTime2) {             console.log("点击了范围之后的时间")           } else {             console.log("点击了范围内的空白,直接加上一个")           }           arr = [...arr, curSelectTimeStamp]           console.log(arr)         } else {           // 第一次选择日期,而且双击了,直接单独确定这个           arr = [curSelectTimeStamp]         }         // 此时选择完日前了,半选的日期消费掉了,清空         this.partialSelect = null       } else {         console.log("不是半选情况")          // 即没有点击范围内,又不是半选状态,可能是已经存在一个半选,等待这个日期来闭合范围,也可能是第一次打开点击         if (this.partialSelect) {           // 需要和已存在的半选态日期闭合           const itemTime = new Date(this.partialSelect).getTime()           const itemTime2 = curSelectTimeStamp           const timeArr = [itemTime, itemTime2].sort((a, b) => a - b) // 排序,因为不知道谁在前面           for (let i = timeArr[0]; i <= timeArr[1]; i += 86400000) {             arr.push(i)           }           // 此时确定好范围了,半选的日期消费掉了,清空           this.partialSelect = null         } else if (this.selctDate.length) {           // 存在一个范围,同时点击范围外,此时设置半选           this.day = sDate           this.partialSelect = curSelectTime         } else {           // 不存在一个范围,所以是第一次点击           this.day = sDate           this.partialSelect = curSelectTime         }       }       let filterArr = Array.from(new Set(arr))       filterArr = filterArr.sort((a, b) => a - b)       this.selctDate = filterArr.map((i) => this.formatTime(new Date(i)))       this.$emit("input", this.selctDate)       this.$emit("change", this.selctDate)       this.day = parseInt(sDate)     }, }

本文转载于:

https://juejin.cn/post/7240088790423863353

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

 记录--设计一个可选择不连续的时间范围的日期选择器