基于Vue實(shí)現(xiàn)可選擇不連續(xù)的時(shí)間范圍的日期選擇器
省流:
npm包:sta-datepicker
效果圖
需求
普通的時(shí)間選擇器要么只能單選,要么只能選范圍,不可以隨意選擇若干個(gè)時(shí)間,同時(shí)大多數(shù)現(xiàn)成的時(shí)間選擇器選擇結(jié)束會(huì)收起來(lái),很不方便?,F(xiàn)在需求如下 1、可以自己控制展開收起 2、可以選擇不連續(xù)的多個(gè)時(shí)間范圍的日期 3、可以批量選中日期,不需要一個(gè)個(gè)點(diǎn)擊
實(shí)現(xiàn)過(guò)程
分幾個(gè)步驟,具體可以看源碼
1、生成一個(gè)日歷
頂部為固定的幾個(gè)按鈕,可以綁定切換年份月份的函數(shù)
中間為固定的星期,一個(gè)七個(gè)
底部為具體日期,由三部分組成,即:上個(gè)月底幾天,這個(gè)月整個(gè)月,下個(gè)月初幾天
- 算好平年閏年,輸出當(dāng)前月份第一天是周幾
- 根據(jù)當(dāng)前月份的第一天的星期數(shù),計(jì)算日歷要展示上個(gè)月月底的幾天
- 根據(jù)當(dāng)前月份最后一天的星期數(shù),計(jì)算日歷要展示下個(gè)月月初的幾天
日期部分使用div遍歷三個(gè)數(shù)組,左浮動(dòng)或者彈性盒直接堆起來(lái)即可
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() }, // 設(shè)置算好閏年平年 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() { // 渲染上個(gè)月,第一行 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) } // 渲染下個(gè)月, 最后一行 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、綁定四個(gè)固定的函數(shù)
點(diǎn)擊上一年,下一年,上個(gè)月,下個(gè)月時(shí),需要計(jì)算跨年的情況
// 年份的增減 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、點(diǎn)擊具體日期時(shí),確定狀態(tài)
使用數(shù)組存起當(dāng)前已選的日期,使用一個(gè)變量記錄當(dāng)前半選的日期
通過(guò)一個(gè)函數(shù)isActive
給每個(gè)日期綁定類名,從而在視圖上顯示出來(lái),同時(shí)可以確定狀態(tài)的切換
- 如果點(diǎn)擊了已選日期的數(shù)據(jù),需要剔除,改為空白狀態(tài)
- 如果點(diǎn)擊了半選態(tài)日期,則直接選中當(dāng)前日期,變?yōu)橐堰x日期
- 如果點(diǎn)擊了空白狀態(tài)日期,則可能有兩種情況,一是已存在半選態(tài)日期,等待閉合,而是不存在半選態(tài)日期,當(dāng)前設(shè)置為半選
methods: { // 突出顯示當(dāng)前日期 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 // 通過(guò)類名判斷當(dāng)前是什么狀態(tài) if (clsName.includes("activeRange")) { // 點(diǎn)擊了范圍內(nèi)的數(shù)據(jù),需要剔除 arr = arr.filter((i) => i !== curSelectTimeStamp) } else if (clsName.includes("active") && !clsName.includes("activeRange")) { // 點(diǎn)擊了一個(gè)半選狀態(tài)的日期,準(zhǔn)備擴(kuò)展范圍或者單選一個(gè) if (this.selctDate.length) { const itemTime = arr[0] const itemTime2 = arr[arr.length - 1] const selectTime = curSelectTimeStamp if (selectTime < itemTime) { console.log("點(diǎn)擊了范圍之前的時(shí)間") } else if (selectTime > itemTime2) { console.log("點(diǎn)擊了范圍之后的時(shí)間") } else { console.log("點(diǎn)擊了范圍內(nèi)的空白,直接加上一個(gè)") } arr = [...arr, curSelectTimeStamp] console.log(arr) } else { // 第一次選擇日期,而且雙擊了,直接單獨(dú)確定這個(gè) arr = [curSelectTimeStamp] } // 此時(shí)選擇完日前了,半選的日期消費(fèi)掉了,清空 this.partialSelect = null } else { console.log("不是半選情況") // 即沒(méi)有點(diǎn)擊范圍內(nèi),又不是半選狀態(tài),可能是已經(jīng)存在一個(gè)半選,等待這個(gè)日期來(lái)閉合范圍,也可能是第一次打開點(diǎn)擊 if (this.partialSelect) { // 需要和已存在的半選態(tài)日期閉合 const itemTime = new Date(this.partialSelect).getTime() const itemTime2 = curSelectTimeStamp const timeArr = [itemTime, itemTime2].sort((a, b) => a - b) // 排序,因?yàn)椴恢勒l(shuí)在前面 for (let i = timeArr[0]; i <= timeArr[1]; i += 86400000) { arr.push(i) } // 此時(shí)確定好范圍了,半選的日期消費(fèi)掉了,清空 this.partialSelect = null } else if (this.selctDate.length) { // 存在一個(gè)范圍,同時(shí)點(diǎn)擊范圍外,此時(shí)設(shè)置半選 this.day = sDate this.partialSelect = curSelectTime } else { // 不存在一個(gè)范圍,所以是第一次點(diǎn)擊 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) }, }
以上就是基于Vue實(shí)現(xiàn)可選擇不連續(xù)的時(shí)間范圍的日期選擇器的詳細(xì)內(nèi)容,更多關(guān)于Vue日期選擇器的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue中如何動(dòng)態(tài)設(shè)置css樣式的hover
這篇文章主要介紹了vue中如何動(dòng)態(tài)設(shè)置css樣式的hover,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10vue-cli-service的參數(shù)配置過(guò)程
這篇文章主要介紹了vue-cli-service的參數(shù)配置過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04關(guān)于Nuxt的五種渲染模式的差異和使用場(chǎng)景全解析
這篇文章主要介紹了關(guān)于Nuxt的五種渲染模式的差異和使用場(chǎng)景全解析,在過(guò)去傳統(tǒng)開發(fā)中,頁(yè)面渲染任務(wù)是由服務(wù)端完成的,那么Nuxt是如何渲染的呢,需要的朋友可以參考下2023-04-04element-plus+Vue3實(shí)現(xiàn)表格數(shù)據(jù)動(dòng)態(tài)渲染
在Vue中,el-table是element-ui提供的強(qiáng)大表格組件,可以用于展示靜態(tài)和動(dòng)態(tài)表格數(shù)據(jù),本文主要介紹了element-plus+Vue3實(shí)現(xiàn)表格數(shù)據(jù)動(dòng)態(tài)渲染,感興趣的可以了解一下2024-03-03vue前端開發(fā)輔助函數(shù)狀態(tài)管理詳解示例
vue的應(yīng)用狀態(tài)管理提供了mapState、mapGetters、mapMutations、mapActions四個(gè)輔助函數(shù),所謂的輔助函數(shù)分別對(duì)State、Getters、Mutations、Actions在完成狀態(tài)的使用進(jìn)行簡(jiǎn)化2021-10-10使用Vue動(dòng)態(tài)生成form表單的實(shí)例代碼
這篇文章主要介紹了使用Vue動(dòng)態(tài)生成form表單的實(shí)例代碼,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2018-04-04vue工程全局設(shè)置ajax的等待動(dòng)效的方法
這篇文章主要介紹了vue工程全局設(shè)置ajax的等待動(dòng)效的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-02-02用electron 打包發(fā)布集成vue2.0項(xiàng)目的操作過(guò)程
這篇文章主要介紹了用electron 打包發(fā)布集成vue2.0項(xiàng)目的操作步驟,把electron 加入到自己項(xiàng)目中各種不兼容,升級(jí)版本踩坑無(wú)數(shù)個(gè),今天通過(guò)本文給大家分享下詳細(xì)過(guò)程,需要的朋友可以參考下2022-10-10