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