這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 npm包:sta-datepicker 效果圖 需求 普通的時間選擇器要麼只能單選,要麼只能選範圍,不可以隨意選擇若幹個時間,同時大多數現成的時間選擇器選擇結束會收起來,很不方便。現在需求如下 1、可以自己控制展開收起 2、可以選擇不連續 ...
這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助
- 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) }, }