目录
前言
最近遇到一个需求:需要限制报表下载的日期范围,统一为半个月,防止用户选择范围过广,导致报表生成缓慢。
项目中使用的element-ui的el-date-picker日期选择组件。
实现思路
- 1.由于页面中有12处需要修改,所以需要对el-date-picker进行二次封装。
- 2.el-date-picker提供的picker-options中的disabledDate属性可以对可选日期进行动态禁用与启用。
- 3.disabledDate属性只能针对选择日期的情况,当用户手动输入日期时,需要进行拦截处理。
具体实现
声明了全局组件HalfMonthPicker
组件模板定义
组件中使用v-bind="attrs"和v−on="attrs"和v-on="attrs"和v−on="listeners"进行了属性和事件透传,方便后期维护。
<el-date-picker v-bind="$attrs" v-on="$listeners" :type="type" :range-separator="rangeSeparator" :start-placeholder="startPlaceholder" :end-placeholder="endPlaceholder" :value="value" :picker-options="pickerOptions"></el-date-picker>
定义props属性 type
el-date-picker目前支持的范围属性为daterange和datetimerange,内部使用了校验函数,确保传入的参数值,默认为daterange。
props: { type: { type: String, default: 'daterange', validator(val) { return ['daterange', 'datetimerange'].includes(val) } } }
设置默认属性值
由于页面中组件使用时都传入了自定义的range-separator,start-placeholder,和end-placeholder,其属性值相同,所以在组件内部定义了props,并设置了默认值,避免页面中重复定义。
props: { rangeSeparator: { type: String, default: '至' }, startPlaceholder: { type: String, default: '起止日期' }, endPlaceholder: { type: String, default: '截止日期' } }
定义核心计算属性pickerOptions
基本变量定义
currentFirstDate
首个选中的日期
currentFirstTime
首个选中的日期毫秒数
currentMinTime
小于currentFirstTime半个月的毫秒数
currentMaxTime
大于currentFirstTime半个月的毫秒数
currentTime
disabledDate函数传入的日期值的毫秒数,用于判断是否在currentMinTime与currentMaxTime之间
shortcuts快捷选项
此处按照产品需求,内置了最近一周和最近半个月的快捷选项。
disabledDate实现
如果存在currentFirstDate,将小于半月或超出半月的日期置为不可选中。
如果不存在,则皆可选。
onPick注意事项
1.当maxDate和minDate都不存在
将currentFirstDate置为null,不限制日期选择
2.minDate存在,而maxDate不存在
currentFirstDate = minDate,并限制日期选择为前后半个月
3.maxDate和minDate同时存在
考虑如下情况,type为datetimerange时,即使选中了开始日期和结束日期,如果没有点确定,弹框并不会消失,此时应该可以重新选择新的开始日期,所以需要将currentFirstDate置为null,不在限制日期的选择。
未置为null
置为null
computed: { pickerOptions() { const { value } = this // 选中的首个日期 let currentFirstDate = Array.isArray(value) && value.length === 1 && value[0] ? value[0] : null // 选中的首个日期毫秒数 let currentFirstTime = null // 当前日期毫秒数 let currentTime = null // 当前可选最小日期毫秒数 let currentMinTime = null // 当前可选最大日期毫秒数 let currentMaxTime = null return { // 快捷选项 shortcuts: [ { text: '最近一周', onClick(picker) { const end = new Date() const start = new Date() start.setTime(start.getTime() - 3600 * 1000 * 24 * 6) picker.$emit('pick', [start, end]) } }, { text: '最近半月', onClick(picker) { const end = new Date() const start = new Date() start.setTime(start.getTime() - 3600 * 1000 * 24 * 14) picker.$emit('pick', [start, end]) } } ], // 禁选逻辑 disabledDate(date) { if (currentFirstDate) { currentFirstTime = new Date(currentFirstDate).getTime() currentTime = new Date(date).getTime() currentMinTime = currentFirstTime - 3600 * 1000 * 24 * 15 currentMaxTime = currentFirstTime + 3600 * 1000 * 24 * 15 // 确保当前可选日期在半月之间 return !(currentTime > currentMinTime && currentTime < currentMaxTime) } return false }, // 选中项 onPick({ maxDate, minDate }) { // console.log(maxDate) currentFirstDate = !maxDate ? minDate : null } } } }
处理手动输入的情况
考虑如下场景,当用户选择在input框中手动输入日期时,pickerOptions中的disabledDate禁选属性便无法对用户产生拦截作用,此时便需要通过监听value属性的变化,当newVal间隔大于半个月时,重置回oldVal。
watch: { // 处理手动输入的情况 value: { handler(newVal, oldVal) { if (Array.isArray(newVal) && newVal.length === 2) { if (this.compareHalfMonthInterval(newVal[0], newVal[1])) { this.$message.warning('日期间隔不能超过半个月') // 重置为oldVal或null this.$emit('input', oldVal || null) } } }, immediate: true } }, methods: { /** * 比较时间是否超出半个月 * @param {*} startDate 开始时间 * @param {*} endDate 结束时间 * @returns { boolean } true为超出半个月 */ compareHalfMonthInterval(startDate, endDate) { if (!startDate || !endDate) { return false } const startTime = new Date(startDate).getTime() const endTime = new Date(endDate).getTime() return (endTime - startTime) > 3600 * 1000 * 24 * 15 } }
页面中使用
使用前
使用后
使用效果
选择开始日期
选择结束日期
完整代码实现
<template> <el-date-picker v-bind="$attrs" v-on="$listeners" :type="type" :range-separator="rangeSeparator" :start-placeholder="startPlaceholder" :end-placeholder="endPlaceholder" :value="value" :picker-options="pickerOptions"></el-date-picker> </template>
<script> export default { name: 'HalfMonthPicker', props: { type: { type: String, default: 'daterange', validator(val) { return ['daterange', 'datetimerange'].includes(val) } }, value: { type: Array, default: () => [] }, rangeSeparator: { type: String, default: '至' }, startPlaceholder: { type: String, default: '起止日期' }, endPlaceholder: { type: String, default: '截止日期' } }, computed: { pickerOptions() { const { value } = this // 选中的首个日期 let currentFirstDate = Array.isArray(value) && value.length === 1 && value[0] ? value[0] : null // 选中的首个日期毫秒数 let currentFirstTime = null // 当前日期毫秒数 let currentTime = null // 当前可选最小日期毫秒数 let currentMinTime = null // 当前可选最大日期毫秒数 let currentMaxTime = null return { // 快捷选项 shortcuts: [ { text: '最近一周', onClick(picker) { const end = new Date() const start = new Date() start.setTime(start.getTime() - 3600 * 1000 * 24 * 6) picker.$emit('pick', [start, end]) } }, { text: '最近半月', onClick(picker) { const end = new Date() const start = new Date() start.setTime(start.getTime() - 3600 * 1000 * 24 * 14) picker.$emit('pick', [start, end]) } } ], // 禁选逻辑 disabledDate(date) { if (currentFirstDate) { currentFirstTime = new Date(currentFirstDate).getTime() currentTime = new Date(date).getTime() currentMinTime = currentFirstTime - 3600 * 1000 * 24 * 15 currentMaxTime = currentFirstTime + 3600 * 1000 * 24 * 15 // 确保当前可选日期在半月之间 return !(currentTime > currentMinTime && currentTime < currentMaxTime) } return false }, // 选中项 onPick({ maxDate, minDate }) { // console.log(maxDate) currentFirstDate = !maxDate ? minDate : null } } } }, watch: { // 处理手动输入的情况 value: { handler(newVal, oldVal) { if (Array.isArray(newVal) && newVal.length === 2) { if (this.compareHalfMonthInterval(newVal[0], newVal[1])) { this.$message.warning('日期间隔不能超过半个月') // 重置为oldVal或null this.$emit('input', oldVal || null) } } }, immediate: true } }, methods: { /** * 比较时间是否超出半个月 * @param {*} startDate 开始时间 * @param {*} endDate 结束时间 * @returns { boolean } true为超出半个月 */ compareHalfMonthInterval(startDate, endDate) { if (!startDate || !endDate) { return false } const startTime = new Date(startDate).getTime() const endTime = new Date(endDate).getTime() return (endTime - startTime) > 3600 * 1000 * 24 * 15 } } } </script>
到此这篇关于el-date-picker日期范围限制的实现的文章就介绍到这了,更多相关el-date-picker日期范围限制内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!