基于element ui的el-date-picker 日、周、月粒度切换时间选择器
先上效果图

需求
- 粒度—时间选择器联动
- 时间周期不能大于今天。(所以今天以后的时间都不能选)
- 周粒度——因为一周没过完,所以不能选当前周
- 月粒度——因为本月没结束,不能选当前月
- 切换粒度的时候自动选择最近符合的时间。
- 侧边有快捷选择。
根据需求还有个隐藏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="width: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="width: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>

浙公网安备 33010602011771号