element-ui 日期范围组件,时间跨度不能超过一年

需求

日期范围的筛选,开始日期和结束日期不能超过1年(1年固定按365天计算),并且在选定一个时间的时候计算可选的日期范围,不在范围内的日期要置灰不可选中。如下图:

查看element-uiDatePicker组件的属性、事件、方法,发现组件提供了Picker Options属性配置项

使用disabledDateonPick配置项

实现代码

这里有一个需要注意的点,可选择的日期范围是根据用户选择的第一个日期动态计算出来的,所以,我们应该吧Picker Options放到计算属性computed中返回。

下面展示我的日期范围筛选的基础控件代码(该控件集成在业务架构中,无关代码可自行忽略,可直接定位到pickerOptions部分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
<template>
<el-form
ref="form"
:rules="rules"
:model="controlForm"
:label-width="itemData.labelWidth"
:label-position="itemData.labelPosition"
>
<el-form-item
:label="itemData.showLabel ? itemData.fieldLabel : ''"
:prop="propName"
>
<el-date-picker
:style="{ width: itemData.rightWidth }"
v-model="controlForm.value"
:format="itemData.format || 'yyyy-MM-dd'"
:value-format="itemData.format || 'yyyyMMdd'"
align="right"
type="daterange"
unlink-panels
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
:picker-options="pickerOptions"
:readonly="isDisable"
:editable="itemData.editable"
:clearable="!itemData.required"
@change="handleChange"
></el-date-picker>
</el-form-item>
</el-form>
</template>

<script>
import moment from "moment";
import { isObject, getWeekStartDate, getWeekEndDate } from '@/libs/utils'

export default {
name: 'Control-RangeDate',
props: {
itemData: {
type: Object,
default: () => { }
}
},
components: {},
data() {
return {
isDisable: false,
controlForm: {
value: ''
},
rules: {
value: [
{
required: true,
message: `请选择${this.itemData.placeholder || this.itemData.fieldLabel}`,
trigger: 'blur'
}
]
},
pickTime: null
}
},
computed: {
propName() {
let name = '';
if (this.itemData.isNotNull === 1) {
name = 'value'
}
return name
},
// pick-option 采用计算属性的方式
pickerOptions() {
let _this = this
return {
disabledDate(time) {
if (_this.pickTime) {
const curTime = moment(moment(_this.pickTime).format('YYYY-MM-DD')).valueOf();
// pickTime 前后 365 天 && 不大于今天
const start = new Date(curTime - 3600 * 1000 * 24 * 365)
const end = new Date(curTime + 3600 * 1000 * 24 * 365)
return time.getTime() > Date.now() || time.getTime() < start || time.getTime() > end
}
return time.getTime() > Date.now()
},
onPick({ maxDate, minDate }) {
if (!maxDate) {
_this.pickTime = minDate
}
},
shortcuts: [
{
text: '今天',
onClick(picker) {
const end = new Date()
const start = new Date(new Date(new Date().setHours(0, 0, 0, 0)))
picker.$emit('pick', [start, end])
}
},
{
text: '昨天',
onClick(picker) {
const end = new Date()
const start = new Date(new Date(new Date().setHours(0, 0, 0, 0)) - 3600 * 1000 * 24 * 1)
end.setTime(start.getTime() + (3600 * 1000 * 24 * 1 - 1))
picker.$emit('pick', [start, end])
}
},
{
text: '本周',
onClick(picker) {
let end = new Date()
let start = new Date()
start = getWeekStartDate(new Date())
end = getWeekEndDate(new Date())
end.setTime(end.getTime() + (3600 * 1000 * 24 * 1 - 1))
picker.$emit('pick', [start, end])
}
},
{
text: '最近一周',
onClick(picker) {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() + (3600 * 1000 * 24 * 7))
picker.$emit('pick', [start, end])
}
},
{
text: '最近一个月',
onClick(picker) {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() + (3600 * 1000 * 24 * 30))
picker.$emit('pick', [start, end])
}
},
{
text: '最近三个月',
onClick(picker) {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() + (3600 * 1000 * 24 * 90))
picker.$emit('pick', [start, end])
}
},
]
}
}
},
watch: {
itemData: {
handler(newV) {
this.isDisable = newV.readonly
},
deep: true,
immediate: true
}
},
created() { },
mounted() { },
methods: {
// 移除校验
clearVerify() {
this.$refs.form.clearValidate()
},

// 初始化带入值
initVal(obj = {}) {
this.clearVerify();
if (isObject(obj)) {
this.controlForm.value = obj[this.itemData.fieldName]
this.itemData.controlData = obj[this.itemData.fieldName]
// this.$emit('update:controlData', obj[this.itemData.fieldName])
}
},

// 初始化默认值
updata() {
this.clearVerify()
this.controlForm.value = this.itemData.defaultValue
this.itemData.controlData = this.itemData.defaultValue
},

// 重置 - 恢复成默认值
reset() {
this.controlForm.value = this.itemData.defaultValue
this.itemData.controlData = this.itemData.defaultValue
},

handleChange(val) {
this.itemData.controlData = val
this.$emit('update:controlData', val || '')
},

verifyForm() {
let isPass = true
this.$refs.form.validate((valid) => {
if (!valid) {
isPass = false
}
})
return isPass
}
},
updated() { },
beforeDestroy() { },
}
</script>

<style lang='less' rel='stylesheet/less' scoped>
@import "../common.less";
</style>

主要代码解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
disabledDate(time) {
if (_this.pickTime) {
const curTime = moment(moment(_this.pickTime).format('YYYY-MM-DD')).valueOf();
// pickTime 前后 365 天 && 不大于今天
const start = new Date(curTime - 3600 * 1000 * 24 * 365)
const end = new Date(curTime + 3600 * 1000 * 24 * 365)
return time.getTime() > Date.now() || time.getTime() < start || time.getTime() > end
}
return time.getTime() > Date.now()
},
onPick({ maxDate, minDate }) {
if (!maxDate) {
_this.pickTime = minDate
}
},
}

通过onPick回调函数可以拿到选中的日期pickTime,然后在disabledDate属性中计算并返回可选的日期范围,主要还是依赖computed的计算属性,依赖的data属性发生变化后会重新计算。