先上效果图
需求
- 粒度—时间选择器联动
- 时间周期不能大于今天。(所以今天以后的时间都不能选)
- 周粒度——因为一周没过完,所以不能选当前周
- 月粒度——因为本月没结束,不能选当前月
- 切换粒度的时候自动选择最近符合的时间。
- 侧边有快捷选择。
根据需求还有个隐藏bug 周需要特殊处理选择的日期还有样式
周粒度是一周一周选择,所以需要特殊处理
上代码
父组件使用
<lidu-picker ref="liduPicker" @changeDate="changeDate"></lidu-picker>
import liduPicker from './components/liduPicker'
monted(){
// 默认日粒度 可以父组件调用初始化也可以直接在子组件初始化
// this.$refs['liduPicker'].changeSize(1)
}
组件liduPicker 周粒度的时候需要增加class="is-week-mode"
date-picker的 value-format="yyyy-MM-dd",其他的未测试是否有影响
组件内在最后使用了dateFormat处理时间。没有的请修改
<template> <el-form inline size="medium"> <el-form-item> <el-select v-model="lidu" placeholder="请选择" @change="changeSize"> <el-option label="日粒度" :value="1"></el-option> <el-option label="周粒度" :value="2"></el-option> <el-option label="月粒度" :value="3"></el-option> </el-select> </el-form-item> <el-form-item> <el-date-picker style="300px" v-model="datePicker" :type="lidu == 3 ? 'monthrange' : 'daterange'" align="left" unlink-panels range-separator="至" start-placeholder="开始时间" end-placeholder="结束时间" :picker-options="pickerOptions" value-format="yyyy-MM-dd" @change="changeDate" @focus="setWeekClass" ></el-date-picker> </el-form-item> </el-form> </template> <script> import { dateFormat } from '@/helpers/utils' export default { data() { return { // 粒度 1:日,2:周,3:月 lidu: 1, // 时间区间选择 datePicker: [], pickerOptions: { firstDayOfWeek: 1, shortcuts: [], }, } }, methods: { // 切换粒度 changeSize(val) { this.datePicker = [] let shortcuts = [] // 一天时间 const day = 3600 * 1000 * 24 const date = new Date() const end = date - day // 日粒度 if (val == 1) { // 初始化时间 默认最近7天 this.changeDate([date - day * 7, date - day]) // 昨日 const latelyDay = this.setShortcut('昨日', end, end) // 上周 const curDay = date.getDay() const lastWeek = this.setShortcut('上周', date - day * (7 + curDay), date - day * (1 + curDay)) // 本月 const curMonth = this.setShortcut('本月', new Date().setDate(1), end) // 上月 上个月第一天 ~ 上个月最后一天 const lastMonth = this.setShortcut('上月', new Date(date.getFullYear(), date.getMonth(), 0).setDate(1), new Date().setDate(0)) // 最近一周 const latelyWeek = this.setShortcut('最近7天', date - day * 7, end) // 最近15天 const latelyHalfMonth = this.setShortcut('最近15天', date - day * 15, end) // 最近30天 const latelyMonth = this.setShortcut('最近30天', date - day * 31, end) // 最近90天 const lately3Month = this.setShortcut('最近90天', date - day * 91, end) shortcuts.push(latelyDay, lastWeek, curMonth, lastMonth, latelyWeek, latelyHalfMonth, latelyMonth, lately3Month) // 选择限制 不能选今天以后 this.pickerOptions.disabledDate = time => { return time.getTime() + 86400000 >= Date.now() } } // 周粒度 if (val == 2) { // 初始化时间 默认最近7天 this.changeDate([date - day * 7, date - day]) // 最近7天 const latelyWeek = this.setShortcut('最近7天', date - day * 7, end) // 最近30天 const latelyMonth = this.setShortcut('最近30天', date - day * 31, end) // 最近90天 const lately3Month = this.setShortcut('最近90天', date - day * 91, end) shortcuts.push(latelyWeek, latelyMonth, lately3Month) // 选择限制 不能选今天以后 this.pickerOptions.disabledDate = time => { return time.getTime() + 86400000 >= Date.now() } } // 月粒度 都是到上个月的最后一天 if (val == 3) { const lastMonth1 = new Date(date.getFullYear(), date.getMonth(), 0).setDate(1) // 初始化时间 默认上月 this.changeDate([lastMonth1, lastMonth1]) // 上月 const last1M = this.setShortcut('上月', lastMonth1, lastMonth1) // 今年 const curYear = this.setShortcut('今年', new Date(date.getFullYear(), 0), lastMonth1) // 最近三个月 const last3M = this.setShortcut('最近三个月', new Date(date.getFullYear(), date.getMonth() - 3), lastMonth1) // 最近六个月 const last6M = this.setShortcut('最近六个月', new Date(date.getFullYear(), date.getMonth() - 6), lastMonth1) shortcuts.push(last1M, curYear, last3M, last6M) // 选择限制 不能选上个月最后一天之后 this.pickerOptions.disabledDate = time => { return time.getTime() + 86400000 >= new Date().setDate(0) } } // console.log('快捷设置:', shortcuts) this.pickerOptions.shortcuts = shortcuts }, setShortcut(text, start, end) { return { text, onClick(picker) { picker.$emit('pick', [dateFormat(new Date(start), 'YYYY-MM-dd'), dateFormat(new Date(end), 'YYYY-MM-dd')]) }, } }, // 所选时间 changeDate(date) { if (!date) return // 日粒度 if (this.lidu == 1) { date = [dateFormat(new Date(date[0]), 'YYYY-MM-dd'), dateFormat(new Date(date[1]), 'YYYY-MM-dd')] this.datePicker = this.datePicker.length ? this.datePicker : date } // 周粒度 if (this.lidu == 2) { // 取出开始时间和结束时间分别是周几 const day = 3600 * 1000 * 24 const yesterday = new Date() - day const start = new Date(date[0]) const end = new Date(date[1]) // 开始时间是距离周一天数 const startDay = start.getDay() == 0 ? 6 : start.getDay() - 1 // 结束时间是距离周日天数 const endDay = end.getDay() == 0 ? 6 : end.getDay() - 1 // 距离上周一天数 const monDay = 13 - new Date().getDay() const lastMonday = new Date() - day * monDay // 距离上周日天数 const sunDay = new Date().getDay() == 0 ? 7 : new Date().getDay() const lastSunday = new Date() - day * sunDay const res = [] // 计算所选开始时间的周一 (判断当前所选日期的周一是否 > 上周一) res[0] = Number(start) - day * startDay > Number(lastMonday) ? Number(lastMonday) : Number(start) - day * startDay // 计算所选结束时间的周日 (判断当前所选日期的周日是否 > 上周日) res[1] = Number(end) + day * (6 - endDay) > Number(lastSunday) ? Number(lastSunday) : Number(end) + day * (6 - endDay) this.datePicker = [dateFormat(new Date(res[0]), 'YYYY-MM-dd'), dateFormat(new Date(res[1]), 'YYYY-MM-dd')] } // 月粒度 if (this.lidu == 3) { const endTime = new Date(date[1]) endTime.setMonth(endTime.getMonth() + 1) const endDay = endTime.setDate(0) // console.log('结束时间的月底', dateFormat(new Date(endDay), 'YYYY-MM-dd')) this.datePicker = [dateFormat(new Date(date[0]), 'YYYY-MM-dd'), dateFormat(new Date(endDay), 'YYYY-MM-dd')] } // console.log('this.datePicker',this.datePicker) this.$emit('changeDate', this.lidu, this.datePicker) }, // 如果是周粒度的时候 首次进入需要绑定样式 is-week-mode setWeekClass(event) { if (this.lidu == 2 && event.picker && event.picker.$children[0].$el.className != 'el-date-table is-week-mode') { // console.log(event.picker) event.picker.$children.forEach(r => { // console.log(r.$el) r.$el.className = `el-date-table is-week-mode` }) } else if (this.lidu != 2 && event.picker && event.picker.$children[0].$el.className == 'el-date-table is-week-mode') { event.picker.$children.forEach(r => { // console.log(r.$el) r.$el.className = `el-date-table` }) } }, }, mounted() { // 默认日粒度 this.changeSize(1) }, } </script> <style></style>
<template>
<el-form inline size="medium">
<el-form-item>
<el-select v-model="lidu" placeholder="请选择" @change="changeSize">
<el-option label="日粒度" :value="1"></el-option>
<el-option label="周粒度" :value="2"></el-option>
<el-option label="月粒度" :value="3"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-date-picker
style="300px"
v-model="datePicker"
:type="lidu == 3 ? 'monthrange' : 'daterange'"
align="left"
unlink-panels
range-separator="至"
start-placeholder="开始时间"
end-placeholder="结束时间"
:picker-options="pickerOptions"
value-format="yyyy-MM-dd"
@change="changeDate"
@focus="setWeekClass"
></el-date-picker>
</el-form-item>
</el-form>
</template>
<script>
import { dateFormat } from '@/helpers/utils'
export default {
data() {
return {
// 粒度 1:日,2:周,3:月
lidu: 1,
// 时间区间选择
datePicker: [],
pickerOptions: {
firstDayOfWeek: 1,
shortcuts: [],
},
}
},
methods: {
// 切换粒度
changeSize(val) {
this.datePicker = []
let shortcuts = []
// 一天时间
const day = 3600 * 1000 * 24
const date = new Date()
const end = date - day
// 日粒度
if (val == 1) {
// 初始化时间 默认最近7天
this.changeDate([date - day * 7, date - day])
// 昨日
const latelyDay = this.setShortcut('昨日', end, end)
// 上周
const curDay = date.getDay()
const lastWeek = this.setShortcut('上周', date - day * (7 + curDay), date - day * (1 + curDay))
// 本月
const curMonth = this.setShortcut('本月', new Date().setDate(1), end)
// 上月 上个月第一天 ~ 上个月最后一天
const lastMonth = this.setShortcut('上月', new Date(date.getFullYear(), date.getMonth(), 0).setDate(1), new Date().setDate(0))
// 最近一周
const latelyWeek = this.setShortcut('最近7天', date - day * 7, end)
// 最近15天
const latelyHalfMonth = this.setShortcut('最近15天', date - day * 15, end)
// 最近30天
const latelyMonth = this.setShortcut('最近30天', date - day * 31, end)
// 最近90天
const lately3Month = this.setShortcut('最近90天', date - day * 91, end)
shortcuts.push(latelyDay, lastWeek, curMonth, lastMonth, latelyWeek, latelyHalfMonth, latelyMonth, lately3Month)
// 选择限制 不能选今天以后
this.pickerOptions.disabledDate = time => {
return time.getTime() + 86400000 >= Date.now()
}
}
// 周粒度
if (val == 2) {
// 初始化时间 默认最近7天
this.changeDate([date - day * 7, date - day])
// 最近7天
const latelyWeek = this.setShortcut('最近7天', date - day * 7, end)
// 最近30天
const latelyMonth = this.setShortcut('最近30天', date - day * 31, end)
// 最近90天
const lately3Month = this.setShortcut('最近90天', date - day * 91, end)
shortcuts.push(latelyWeek, latelyMonth, lately3Month)
// 选择限制 不能选今天以后
this.pickerOptions.disabledDate = time => {
return time.getTime() + 86400000 >= Date.now()
}
}
// 月粒度 都是到上个月的最后一天
if (val == 3) {
const lastMonth1 = new Date(date.getFullYear(), date.getMonth(), 0).setDate(1)
// 初始化时间 默认上月
this.changeDate([lastMonth1, lastMonth1])
// 上月
const last1M = this.setShortcut('上月', lastMonth1, lastMonth1)
// 今年
const curYear = this.setShortcut('今年', new Date(date.getFullYear(), 0), lastMonth1)
// 最近三个月
const last3M = this.setShortcut('最近三个月', new Date(date.getFullYear(), date.getMonth() - 3), lastMonth1)
// 最近六个月
const last6M = this.setShortcut('最近六个月', new Date(date.getFullYear(), date.getMonth() - 6), lastMonth1)
shortcuts.push(last1M, curYear, last3M, last6M)
// 选择限制 不能选上个月最后一天之后
this.pickerOptions.disabledDate = time => {
return time.getTime() + 86400000 >= new Date().setDate(0)
}
}
// console.log('快捷设置:', shortcuts)
this.pickerOptions.shortcuts = shortcuts
},
setShortcut(text, start, end) {
return {
text,
onClick(picker) {
picker.$emit('pick', [dateFormat(new Date(start), 'YYYY-MM-dd'), dateFormat(new Date(end), 'YYYY-MM-dd')])
},
}
},
// 所选时间
changeDate(date) {
if (!date) return
if (this.lidu == 1) {
date = [dateFormat(new Date(date[0]), 'YYYY-MM-dd'), dateFormat(new Date(date[1]), 'YYYY-MM-dd')]
this.datePicker = this.datePicker.length ? this.datePicker : date
}
if (this.lidu == 2) {
// 取出开始时间和结束时间分别是周几
const day = 3600 * 1000 * 24
const yesterday = new Date() - day
const start = new Date(date[0])
const end = new Date(date[1])
// 开始时间是距离周一天数
const startDay = start.getDay() == 0 ? 6 : start.getDay() - 1
// 结束时间是距离周日天数
const endDay = end.getDay() == 0 ? 6 : end.getDay() - 1
// 距离上周一天数
const monDay = 13 - new Date().getDay()
const lastMonday = new Date() - day * monDay
// 距离上周日天数
const sunDay = new Date().getDay() == 0 ? 7 : new Date().getDay()
const lastSunday = new Date() - day * sunDay
const res = []
// 计算所选开始时间的周一 (判断当前所选日期的周一是否 > 上周一)
res[0] = Number(start) - day * startDay > Number(lastMonday) ? Number(lastMonday) : Number(start) - day * startDay
// 计算所选结束时间的周日 (判断当前所选日期的周日是否 > 上周日)
res[1] = Number(end) + day * (6 - endDay) > Number(lastSunday) ? Number(lastSunday) : Number(end) + day * (6 - endDay)
this.datePicker = [dateFormat(new Date(res[0]), 'YYYY-MM-dd'), dateFormat(new Date(res[1]), 'YYYY-MM-dd')]
}
if (this.lidu == 3) {
const endTime = new Date(date[1])
endTime.setMonth(endTime.getMonth() + 1)
const endDay = endTime.setDate(0)
// console.log('结束时间的月底', dateFormat(new Date(endDay), 'YYYY-MM-dd'))
this.datePicker = [dateFormat(new Date(date[0]), 'YYYY-MM-dd'), dateFormat(new Date(endDay), 'YYYY-MM-dd')]
}
// console.log('this.datePicker',this.datePicker)
this.$emit('changeDate', this.lidu, this.datePicker)
},
// 如果是周粒度的时候 首次进入需要绑定样式 is-week-mode
setWeekClass(event) {
if (this.lidu == 2 && event.picker && event.picker.$children[0].$el.className != 'el-date-table is-week-mode') {
// console.log(event.picker)
event.picker.$children.forEach(r => {
// console.log(r.$el)
r.$el.className = `el-date-table is-week-mode`
})
} else if (this.lidu != 2 && event.picker && event.picker.$children[0].$el.className == 'el-date-table is-week-mode') {
event.picker.$children.forEach(r => {
// console.log(r.$el)
r.$el.className = `el-date-table`
})
}
},
},
mounted() {
// 默认日粒度
this.changeSize(1)
},
}
</script>
<style></style>