时间选择器实现精确到时分禁用多个时间段并能动态更新禁用时间段,超级详细(附完整代码及文件)
文章目录
- 需求描述
- 精确到年月日
- 实现精确到时分
- 完整代码文件
需求描述
最近遇到了一个关于日期选择器动态禁用多个时间段的组件需求:
需求描述:在可新增的动态表格中,新增一条数据,该数据中的开始日期和结束日期可选择范围由整个表格的每条数据的开始日期和结束日期决定,选择的时间段不能有重叠,开始日期和结束日期可为同一天,时间格式为yyyy-MM-dd。
解决关键:需要用到element日期选择器组件的属性picker-options来处理需要禁用的时间段(我使用到了XUI,换回element同样ok)。
精确到年月日
首先搭建简单的vue页面,此时开始日期与结束日期选择器日期可以任意选择,表格1为初始的日期表格数据,表2为过滤掉错误数据后的日期表格数据。代码如下:
<template><div><div class="my-start-date"><x-date :value="startDate" :editable="false" format="yyyy-MM-dd HH:mm" value-format="yyyy-MM-dd HH:mm" type="datetime" :picker-options="startPickerOptions" placeholder="选择开始时间" @change="startValueChangeEvent" @focus="startFocus"></x-date></div><div class="my-end-date"><x-date :value="endDate" :editable="false" format="yyyy-MM-dd HH:mm" value-format="yyyy-MM-dd HH:mm" type="datetime" :picker-options="endPickerOptions" placeholder="选择结束时间" @change="endValueChangeEvent" @focus="endFocus"></x-date></div><div><el-button style="width: 20%; margin: 10px;" type="primary" @click="addDateRange">新增时间段</el-button><div><x-vxe-tableclass="origin-table":colConfigs="colConfigs":tableData="dateList"seqType="checkbox":pagination="{total:dateList.length}"></x-vxe-table></div><div><x-vxe-tableclass="handled-table":colConfigs="colConfigs":tableData="filterDataList"seqType="checkbox":pagination="{total:filterDataList.length}"></x-vxe-table></div></div></div>
</template><script>export default {name: 'ApaasCustomTestPage1',components: {},data() {return {finalSelectableRange: '', // 存储时分秒时间段startDate: '', // 绑定的开始时间endDate: '', // 绑定的结束时间startPickerOptions: {},endPickerOptions: {},colConfigs: [ // 表格列配置{prop: 'dayStart',label: '开始日期'},{prop: 'dayEnd',label: '结束日期'}],dateList: [ // 模拟初始数据{dayStart: '2022-03-11',dayEnd: '2022-03-14'},{dayStart: 'undefined',dayEnd: ''},{dayStart: 'NaN-NaN-NaN',dayEnd: '2022-04-08'},{dayStart: 'Mon Feb 29 2022 00:00:00 GMT+0800 (中国标准时间)',dayEnd: '2022-03-05'},{dayStart: '2022-03-18',dayEnd: '2022-03-20'},{dayStart: '2022-03-24',dayEnd: '2022-03-25'}],filterDataList: [] // 过滤后的数据}},computed: {},watch: {},mounted() {// 处理初始数据this.filterDate()},created() {},methods: {/*** -----------------------------------------------------组件方法-----------------------------------------------------------** 控制时间段禁用的主要逻辑是在时间选择器的focus方法中处理*/// 开始时间组件的focus方法startFocus() {},// 开始时间组件的change方法,只要选中的值改变,不管是否点击了确定按钮(关闭弹窗),都会触发startValueChangeEvent(value) {console.log('开始时间的值', value)this.startDate = value},// 结束时间组件的focus方法endFocus() {},// 结束时间组件的change方法endValueChangeEvent(value) {console.log('结束时间的值:', value)this.endDate = value},/*** ---------------------------------------------------按钮相关方法-----------------------------------------------------------*/// 新增时间段addDateRange() {if (this.startDate && this.endDate) {this.dateList.push({dayStart: this.startDate,dayEnd: this.endDate})// 处理数据this.filterDate()this.$message({type: 'success',message: '时间段添加成功!'})} else {this.$message({type: 'warning',message: '数据有误,请重新选择时间!'})}},// 数据过滤 返回数据正常的数据,此方法可用作过滤接口返回数据filterDate() {this.filterDataList = []// 对初始数据进行深拷贝,避免数据污染let tempArr = this.deepCopy(this.dateList)tempArr.forEach(item => {if (item.dayStart && item.dayStart !== 'NaN-NaN-NaN' && item.dayEnd && item.dayEnd !== 'NaN-NaN-NaN') {item.dayStart = this.changeType(item.dayStart)item.dayEnd = this.changeType(item.dayEnd)this.filterDataList.push(item)}})},/*** ------------------------------------------------工具函数--------------------------------------------------------*/// 转换时间格式,type可不传 此方法可继续拆分实现获取单独的年、月、日、时、分、秒 此处简略changeType(val, type) {let date = new Date(val)let Y = date.getFullYear()let M = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : (date.getMonth() + 1)let D = date.getDate() < 10 ? ('0' + date.getDate()) : date.getDate()val = Y + '-' + M + '-' + Dif (type === 'yyyy-MM-dd HH:mm') {let h = (date.getHours() < 10 ? '0' + (date.getHours()) : date.getHours())let m = (date.getMinutes() < 10 ? '0' + (date.getMinutes()) : date.getMinutes())val = val + ' ' + h + ':' + m}return val},// 获取单独的小时(24小时制)getHourChange(val) {let date = new Date(Date.parse(val))return date.getHours() < 10 ? '0' + (date.getHours()) : date.getHours()},// 获取单独的分钟getMinutesChange(val) {let date = new Date(Date.parse(val))return date.getMinutes() < 10 ? '0' + (date.getMinutes()) : date.getMinutes()},// 深拷贝deepCopy (obj) {const result = Array.isArray(obj) ? [] : {}for (var key in obj) {if (obj.hasOwnProperty(key)) {if (typeof obj[key] === 'object' && obj[key] !== null) {if (obj[key] instanceof RegExp) {result[key] = obj[key]} else {result[key] = this.deepCopy(obj[key]) // 递归复制}} else {result[key] = obj[key]}}}return result}}
}</script><style lang="scss" scoped>
.origin-table {height: 400px;overflow: auto;
}
.handled-table {height: 400px;overflow: auto;
}
.my-start-date {width: 40%;margin: 10px;/* 修改被禁用的时间背景色,需注意会不会影响全局样式 *//deep/ .el-date-table td.disabled div {background-color: pink !important;}
}
.my-end-date {width: 40%;margin: 10px;
}
</style>
页面说明如图:
首先先禁用当天日期之前的日期
// 开始时间组件的focus方法startFocus() {// 禁用当天日期之前的日期this.startPickerOptions = Object.assign({}, this.startPickerOptions, {disabledDate: (time) => {let disable = time < new Date(new Date().setHours(0, 0, 0, 0)) // 获取当天0点return disable}})},
首先,我们实现根据是否有结束日期来限定开始时间时间选择器的禁用时间段,代码如下:
// 开始时间组件的focus方法startFocus() {// 1. 将多个时间段按时间正序排序this.filterDataList.sort(function(a, b) {// sort按时间正序排序return Date.parse(a.dayEnd) - Date.parse(b.dayEnd)})// 2. 判断是否存在结束日期let today = this.changeType(new Date()) // 记录当前日期,格式为yyyy-MM-dd// 存在结束日期if (this.endDate) {let changeEndDate = this.changeType(this.endDate) // 转为yyyy-MM-dd格式,用做字符串大小对比console.log('处理后的日期:', changeEndDate, today)if (this.filterDataList.length === 0) {// 时间段数组无数据,不需做处理} else {for (let i = 0; i < this.filterDataList.length; i++) {if (this.filterDataList.length === 1) {// 长度为1时if (changeEndDate > this.filterDataList[0].dayEnd) {// 结束时间大于这个时间段的结束时间this.limitedStartDate = this.filterDataList[0].dayStart} else {this.limitedStartDate = today}} else {// 长度大于1时// 结束时间大于等于当前时间段的结束时间并且结束时间小于等于下一个时间段的结束时间if (i < this.filterDataList.length - 1 && changeEndDate >= this.filterDataList[i].dayEnd && changeEndDate <= this.filterDataList[i + 1].dayStart) {this.limitedStartDate = this.filterDataList[i].dayEnd} else if (changeEndDate < this.filterDataList[0].dayStart) {// 结束时间在第一个时间段之前this.limitedStartDate = today} else if (changeEndDate > this.filterDataList[this.filterDataList.length - 1].dayEnd) {// 结束时间在最后一个时间段之后this.limitedStartDate = this.filterDataList[this.filterDataList.length - 1].dayEnd}}}}// 3. 遍历过滤后的数据并禁用相应的时间段this.startPickerOptions = Object.assign({}, this.startPickerOptions, {disabledDate: (time) => {let disable // 定义禁用字段let finalStart = '' // 定义临时开始日期if (today < changeEndDate) {if (today < this.limitedStartDate) {disable = time < new Date(this.limitedStartDate)finalStart = this.limitedStartDate} else {disable = time < new Date(today).getTime() - 8.64e7 // 减去一天8.64e7,使得可以选择和结束日期同一天finalStart = today}} else {disable = time < new Date(today).getTime() - 8.64e7 // 减去一天8.64e7finalStart = today}// 此数组存储的为根据结束时间限定的最终的禁用时间段let tempList = [{dayStart: finalStart,dayEnd: changeEndDate}]tempList.forEach(item => {disable = disable || (time.getTime() > new Date(item.dayEnd).getTime())})return disable}})} else {// 结束时间为空,遍历过滤后的数据并禁用相应的时间段this.startPickerOptions = Object.assign({}, this.startPickerOptions, {disabledDate: (time) => {let disable = time < new Date(new Date().setHours(0, 0, 0, 0)) // 获取当天0点this.filterDataList.forEach(item => {disable = disable || (time.getTime() > new Date(item.dayStart).getTime() - 8.64e7 && time.getTime() < new Date(item.dayEnd).getTime()) // 减去一天8.64e7})return disable}})}},
接下来,如法炮制,实现根据开始时间来限定结束时间时间选择器的禁用时间段,代码如下:
// 结束时间组件的focus方法endFocus() {// 1. 将多个时间段按时间逆序排序this.filterDataList.sort(function(a, b) {// sort按时间逆序排序return Date.parse(a.dayStart) - Date.parse(b.dayStart)})// 2. 判断是否存在开始日期let today = this.changeType(new Date()) // 记录当前日期,格式为yyyy-MM-ddif (this.startDate) {let changeStartDate = this.changeType(this.startDate) // 转为yyyy-MM-dd格式,用做字符串大小对比console.log('处理后的日期:', changeStartDate, today)if (this.filterDataList.length === 0) {// 时间段数组无数据,不需做处理} else {for (let i = 0; i < this.filterDataList.length; i++) {if (this.filterDataList.length === 1) {// 长度为1时if (changeStartDate > this.filterDataList[0].dayEnd) {// 开始时间大于这个时间段的结束时间this.limitedEndDate = ''} else {this.limitedEndDate = this.filterDataList[0].dayStart}} else {// 长度大于1时// 开始时间大于等于当前时间段的开始时间并且开始时间小于等于下一个时间段的开始时间if (i < this.filterDataList.length - 1 && changeStartDate >= this.filterDataList[i].dayEnd && changeStartDate <= this.filterDataList[i + 1].dayStart) {this.limitedEndDate = this.filterDataList[i + 1].dayStart} else if (changeStartDate < this.filterDataList[0].dayStart) {// 开始时间在第一个时间段之前this.limitedEndDate = this.filterDataList[0].dayStart} else if (changeStartDate > this.filterDataList[this.filterDataList.length - 1].dayEnd) {// 开始时间在最后一个时间段之后this.limitedEndDate = ''}}}}// 3. 遍历过滤后的数据并禁用相应的时间段this.endPickerOptions = Object.assign({}, this.endPickerOptions, {disabledDate: (time) => {let disable // 定义禁用字段if (changeStartDate) {// 结束日期可与开始日期为同一天disable = time.getTime() < new Date(Date.parse(changeStartDate)).getTime() - 8.64e7} else {disable = time.getTime() < new Date(today).getTime() - 8.64e7}let tempList = [{dayStart: changeStartDate,dayEnd: this.limitedEndDate}]tempList.forEach(item => {if (!item.dayEnd) {} else {disable = disable || (time.getTime() > new Date(Date.parse(item.dayEnd)).getTime() - 8.64e7) // 减去一天8.64e7}})return disable}})} else {// 无开始时间this.endPickerOptions = Object.assign({}, this.endPickerOptions, {disabledDate: (time) => {let disable = time < new Date(new Date().setHours(0, 0, 0, 0)) // 获取当天0点this.filterDataList.forEach(item => {disable = disable || (time.getTime() > new Date(item.dayStart).getTime() - 8.64e7 && time.getTime() < new Date(item.dayEnd).getTime())})return disable}})}},
到这里,就实现了动态禁用时间段的需求,完整代码如下:
<template><div><div class="my-start-date"><x-date :value="startDate" :editable="false" format="yyyy-MM-dd HH:mm" value-format="yyyy-MM-dd HH:mm" type="datetime" :picker-options="startPickerOptions" placeholder="选择开始时间" @change="startValueChangeEvent" @focus="startFocus"></x-date></div><div class="my-end-date"><x-date :value="endDate" :editable="false" format="yyyy-MM-dd HH:mm" value-format="yyyy-MM-dd HH:mm" type="datetime" :picker-options="endPickerOptions" placeholder="选择结束时间" @change="endValueChangeEvent" @focus="endFocus"></x-date></div><div><el-button style="width: 20%; margin: 10px;" type="primary" @click="addDateRange">新增时间段</el-button><div><x-vxe-tableclass="origin-table":colConfigs="colConfigs":tableData="dateList"seqType="checkbox":pagination="{total:dateList.length}"></x-vxe-table></div><div><x-vxe-tableclass="handled-table":colConfigs="colConfigs":tableData="filterDataList"seqType="checkbox":pagination="{total:filterDataList.length}"></x-vxe-table></div></div></div>
</template><script>export default {name: 'ApaasCustomTestPage1',components: {},data() {return {finalSelectableRange: '', // 存储时分秒时间段startDate: '', // 绑定的开始时间endDate: '', // 绑定的结束时间limitedStartDate: '', // focus事件限定的开始时间limitedEndDate: '', // 限定的结束时间startPickerOptions: {},endPickerOptions: {},colConfigs: [ // 表格列配置{prop: 'dayStart',label: '开始日期'},{prop: 'dayEnd',label: '结束日期'}],dateList: [ // 模拟初始数据{dayStart: '2022-03-11',dayEnd: '2022-03-14'},{dayStart: 'undefined',dayEnd: ''},{dayStart: 'NaN-NaN-NaN',dayEnd: '2022-04-08'},{dayStart: 'Mon Feb 29 2022 00:00:00 GMT+0800 (中国标准时间)',dayEnd: '2022-03-05'},{dayStart: '2022-03-18',dayEnd: '2022-03-20'},{dayStart: '2022-03-24',dayEnd: '2022-03-25'}],filterDataList: [] // 过滤后的数据}},computed: {},watch: {},mounted() {// 处理初始数据this.filterDate()},created() {},methods: {/*** -----------------------------------------------------组件方法-----------------------------------------------------------** 控制时间段禁用的主要逻辑是在时间选择器的focus方法中处理*/// 开始时间组件的focus方法startFocus() {// 1. 将多个时间段按时间正序排序this.filterDataList.sort(function(a, b) {// sort按时间正序排序return Date.parse(a.dayEnd) - Date.parse(b.dayEnd)})// 2. 判断是否存在结束日期let today = this.changeType(new Date()) // 记录当前日期,格式为yyyy-MM-dd// 存在结束日期if (this.endDate) {let changeEndDate = this.changeType(this.endDate) // 转为yyyy-MM-dd格式,用做字符串大小对比console.log('处理后的日期:', changeEndDate, today)if (this.filterDataList.length === 0) {// 时间段数组无数据,不需做处理} else {for (let i = 0; i < this.filterDataList.length; i++) {if (this.filterDataList.length === 1) {// 长度为1时if (changeEndDate > this.filterDataList[0].dayEnd) {// 结束时间大于这个时间段的结束时间this.limitedStartDate = this.filterDataList[0].dayStart} else {this.limitedStartDate = today}} else {// 长度大于1时// 结束时间大于等于当前时间段的结束时间并且结束时间小于等于下一个时间段的结束时间if (i < this.filterDataList.length - 1 && changeEndDate >= this.filterDataList[i].dayEnd && changeEndDate <= this.filterDataList[i + 1].dayStart) {this.limitedStartDate = this.filterDataList[i].dayEnd} else if (changeEndDate < this.filterDataList[0].dayStart) {// 结束时间在第一个时间段之前this.limitedStartDate = today} else if (changeEndDate > this.filterDataList[this.filterDataList.length - 1].dayEnd) {// 结束时间在最后一个时间段之后this.limitedStartDate = this.filterDataList[this.filterDataList.length - 1].dayEnd}}}}// 3. 遍历过滤后的数据并禁用相应的时间段this.startPickerOptions = Object.assign({}, this.startPickerOptions, {disabledDate: (time) => {let disable // 定义禁用字段let finalStart = '' // 定义临时开始日期if (today < changeEndDate) {if (today < this.limitedStartDate) {disable = time < new Date(this.limitedStartDate)finalStart = this.limitedStartDate} else {disable = time < new Date(today).getTime() - 8.64e7 // 减去一天8.64e7,使得可以选择和结束日期同一天finalStart = today}} else {disable = time < new Date(today).getTime() - 8.64e7 // 减去一天8.64e7finalStart = today}// 此数组存储的为根据结束时间限定的最终的禁用时间段let tempList = [{dayStart: finalStart,dayEnd: changeEndDate}]tempList.forEach(item => {disable = disable || (time.getTime() > new Date(item.dayEnd).getTime())})return disable}})} else {// 结束时间为空,遍历过滤后的数据并禁用相应的时间段this.startPickerOptions = Object.assign({}, this.startPickerOptions, {disabledDate: (time) => {let disable = time < new Date(new Date().setHours(0, 0, 0, 0)) // 获取当天0点this.filterDataList.forEach(item => {disable = disable || (time.getTime() > new Date(item.dayStart).getTime() - 8.64e7 && time.getTime() < new Date(item.dayEnd).getTime()) // 减去一天8.64e7})return disable}})}},// 开始时间组件的change方法,只要选中的值改变,不管是否点击了确定按钮(关闭弹窗),都会触发startValueChangeEvent(value) {console.log('开始时间的值', value)this.startDate = value},// 结束时间组件的focus方法endFocus() {// 1. 将多个时间段按时间逆序排序this.filterDataList.sort(function(a, b) {// sort按时间逆序排序return Date.parse(a.dayStart) - Date.parse(b.dayStart)})// 2. 判断是否存在开始日期let today = this.changeType(new Date()) // 记录当前日期,格式为yyyy-MM-ddif (this.startDate) {let changeStartDate = this.changeType(this.startDate) // 转为yyyy-MM-dd格式,用做字符串大小对比console.log('处理后的日期:', changeStartDate, today)if (this.filterDataList.length === 0) {// 时间段数组无数据,不需做处理} else {for (let i = 0; i < this.filterDataList.length; i++) {if (this.filterDataList.length === 1) {// 长度为1时if (changeStartDate > this.filterDataList[0].dayEnd) {// 开始时间大于这个时间段的结束时间this.limitedEndDate = ''} else {this.limitedEndDate = this.filterDataList[0].dayStart}} else {// 长度大于1时// 开始时间大于等于当前时间段的开始时间并且开始时间小于等于下一个时间段的开始时间if (i < this.filterDataList.length - 1 && changeStartDate >= this.filterDataList[i].dayEnd && changeStartDate <= this.filterDataList[i + 1].dayStart) {this.limitedEndDate = this.filterDataList[i + 1].dayStart} else if (changeStartDate < this.filterDataList[0].dayStart) {// 开始时间在第一个时间段之前this.limitedEndDate = this.filterDataList[0].dayStart} else if (changeStartDate > this.filterDataList[this.filterDataList.length - 1].dayEnd) {// 开始时间在最后一个时间段之后this.limitedEndDate = ''}}}}// 3. 遍历过滤后的数据并禁用相应的时间段this.endPickerOptions = Object.assign({}, this.endPickerOptions, {disabledDate: (time) => {let disable // 定义禁用字段if (changeStartDate) {// 结束日期可与开始日期为同一天disable = time.getTime() < new Date(Date.parse(changeStartDate)).getTime() - 8.64e7} else {disable = time.getTime() < new Date(today).getTime() - 8.64e7}let tempList = [{dayStart: changeStartDate,dayEnd: this.limitedEndDate}]tempList.forEach(item => {if (!item.dayEnd) {} else {disable = disable || (time.getTime() > new Date(Date.parse(item.dayEnd)).getTime() - 8.64e7) // 减去一天8.64e7}})return disable}})} else {// 无开始时间this.endPickerOptions = Object.assign({}, this.endPickerOptions, {disabledDate: (time) => {let disable = time < new Date(new Date().setHours(0, 0, 0, 0)) // 获取当天0点this.filterDataList.forEach(item => {disable = disable || (time.getTime() > new Date(item.dayStart).getTime() - 8.64e7 && time.getTime() < new Date(item.dayEnd).getTime())})return disable}})}},// 结束时间组件的change方法endValueChangeEvent(value) {console.log('结束时间的值:', value)this.endDate = value},/*** ---------------------------------------------------按钮相关方法-------------------------------------------------*/// 新增时间段addDateRange() {if (this.startDate && this.endDate) {this.dateList.push({dayStart: this.startDate,dayEnd: this.endDate})// 处理数据this.filterDate()this.$message({type: 'success',message: '时间段添加成功!'})} else {this.$message({type: 'warning',message: '数据有误,请重新选择时间!'})}},// 数据过滤 返回数据正常的数据,此方法可用作过滤接口返回数据filterDate() {this.filterDataList = []// 对初始数据进行深拷贝,避免数据污染let tempArr = this.deepCopy(this.dateList)tempArr.forEach(item => {if (item.dayStart && item.dayStart !== 'NaN-NaN-NaN' && item.dayEnd && item.dayEnd !== 'NaN-NaN-NaN') {item.dayStart = this.changeType(item.dayStart)item.dayEnd = this.changeType(item.dayEnd)this.filterDataList.push(item)}})},/*** ------------------------------------------------工具函数--------------------------------------------------------*/// 转换时间格式,type可不传 此方法可继续拆分实现获取单独的年、月、日、时、分、秒 此处简略changeType(val, type) {let date = new Date(val)let Y = date.getFullYear()let M = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : (date.getMonth() + 1)let D = date.getDate() < 10 ? ('0' + date.getDate()) : date.getDate()val = Y + '-' + M + '-' + Dif (type === 'yyyy-MM-dd HH:mm') {let h = (date.getHours() < 10 ? '0' + (date.getHours()) : date.getHours())let m = (date.getMinutes() < 10 ? '0' + (date.getMinutes()) : date.getMinutes())val = val + ' ' + h + ':' + m}return val},// 获取单独的小时(24小时制)getHourChange(val) {let date = new Date(Date.parse(val))return date.getHours() < 10 ? '0' + (date.getHours()) : date.getHours()},// 获取单独的分钟getMinutesChange(val) {let date = new Date(Date.parse(val))return date.getMinutes() < 10 ? '0' + (date.getMinutes()) : date.getMinutes()},// 深拷贝deepCopy (obj) {const result = Array.isArray(obj) ? [] : {}for (var key in obj) {if (obj.hasOwnProperty(key)) {if (typeof obj[key] === 'object' && obj[key] !== null) {if (obj[key] instanceof RegExp) {result[key] = obj[key]} else {result[key] = this.deepCopy(obj[key]) // 递归复制}} else {result[key] = obj[key]}}}return result}}
}</script><style lang="scss" scoped>
.origin-table {height: 400px;overflow: auto;
}
.handled-table {height: 400px;overflow: auto;
}
.my-start-date {width: 40%;margin: 10px;/* 修改被禁用的时间背景色,需注意会不会影响全局样式 *//deep/ .el-date-table td.disabled div {background-color: pink !important;}
}
.my-end-date {width: 40%;margin: 10px;
}
</style>
实现精确到时分
如果我们想继续精确到时分,我们可以使用时间选择器的selectableRange
属性,然后我们需要监听开始时间和结束时间来控制时分的选择范围,相关代码如下:
watch: {startDate: {handler(newVal) {if (!newVal) {return}let today = new Date()if (this.changeType(newVal) === this.changeType(today)) {if (this.endDate && this.changeType(newVal) === this.changeType(this.endDate)) {this.finalStartSelectableRange = this.getHourChange(today) + ':' + this.getMinutesChange(today) + ':00 - ' + this.getHourChange(this.endDate) + ':' + this.getMinutesChange(this.endDate) + ':59'} else {this.finalStartSelectableRange = this.getHourChange(today) + ':' + this.getMinutesChange(today) + ':00 - 23:59:59'}} else {if (this.changeType(newVal) === this.changeType(this.endDate)) {this.finalStartSelectableRange = '00:00:00 - ' + this.getHourChange(this.endDate) + ':' + this.getMinutesChange(this.endDate) + ':59'} else {this.finalStartSelectableRange = '00:00:00 - 23:59:59'}}this.startPickerOptions.selectableRange = this.finalStartSelectableRangethis.$forceUpdate()}},endDate: {handler(newVal) {if (!newVal) {return}let today = new Date()if (this.changeType(newVal) === this.changeType(today)) {if (this.startDate && this.changeType(newVal) === this.changeType(today)) {this.finalEndSelectableRange = this.getHourChange(this.startDate) + ':' + this.getMinutesChange(this.startDate) + ':00 - 23:59:59'} else {this.finalEndSelectableRange = '00:00:00 - 23:59:59'}} else {if (this.changeType(newVal) === this.changeType(this.startDate)) {this.finalEndSelectableRange = this.getHourChange(this.startDate) + ':' + this.getMinutesChange(this.startDate) + ':00 - 23:59:59'} else {this.finalEndSelectableRange = '00:00:00 - 23:59:59'}}this.endPickerOptions.selectableRange = this.finalEndSelectableRangethis.$forceUpdate()}}},
最终的精确到时分控制时间段的完整代码如下:
<template><div><div class="my-start-date"><x-date :value="startDate" :editable="false" format="yyyy-MM-dd HH:mm" value-format="yyyy-MM-dd HH:mm" type="datetime" :picker-options="startPickerOptions" placeholder="选择开始时间" @change="startValueChangeEvent" @focus="startFocus"></x-date></div><div class="my-end-date"><x-date :value="endDate" :editable="false" format="yyyy-MM-dd HH:mm" value-format="yyyy-MM-dd HH:mm" type="datetime" :picker-options="endPickerOptions" placeholder="选择结束时间" @change="endValueChangeEvent" @focus="endFocus"></x-date></div><div><el-button style="width: 20%; margin: 10px;" type="primary" @click="addDateRange">新增时间段</el-button><div><x-vxe-tableclass="origin-table":colConfigs="colConfigs":tableData="dateList"seqType="checkbox":pagination="{total:dateList.length}"></x-vxe-table></div><div><x-vxe-tableclass="handled-table":colConfigs="colConfigs":tableData="filterDataList"seqType="checkbox":pagination="{total:filterDataList.length}"></x-vxe-table></div></div></div>
</template><script>export default {name: 'ApaasCustomTestPage1',components: {},data() {return {finalStartSelectableRange: '00:00:00 - 23:59:59', // 存储时分秒时间段finalEndSelectableRange: '00:00:00 - 23:59:59', // 存储时分秒时间段startDate: '', // 绑定的开始时间endDate: '', // 绑定的结束时间limitedStartDate: '', // focus事件限定的开始时间limitedEndDate: '', // 限定的结束时间startPickerOptions: {},endPickerOptions: {},colConfigs: [ // 表格列配置{prop: 'dayStart',label: '开始日期'},{prop: 'dayEnd',label: '结束日期'}],dateList: [ // 模拟初始数据{dayStart: '2022-03-11',dayEnd: '2022-03-14'},{dayStart: 'undefined',dayEnd: ''},{dayStart: 'NaN-NaN-NaN',dayEnd: '2022-04-08'},{dayStart: 'Mon Feb 29 2022 00:00:00 GMT+0800 (中国标准时间)',dayEnd: '2022-03-05'},{dayStart: '2022-03-18',dayEnd: '2022-03-20'},{dayStart: '2022-03-24',dayEnd: '2022-03-25'}],filterDataList: [] // 过滤后的数据}},computed: {},watch: {startDate: {handler(newVal) {if (!newVal) {return}let today = new Date()if (this.changeType(newVal) === this.changeType(today)) {if (this.endDate && this.changeType(newVal) === this.changeType(this.endDate)) {this.finalStartSelectableRange = this.getHourChange(today) + ':' + this.getMinutesChange(today) + ':00 - ' + this.getHourChange(this.endDate) + ':' + this.getMinutesChange(this.endDate) + ':59'} else {this.finalStartSelectableRange = this.getHourChange(today) + ':' + this.getMinutesChange(today) + ':00 - 23:59:59'}} else {if (this.changeType(newVal) === this.changeType(this.endDate)) {this.finalStartSelectableRange = '00:00:00 - ' + this.getHourChange(this.endDate) + ':' + this.getMinutesChange(this.endDate) + ':59'} else {this.finalStartSelectableRange = '00:00:00 - 23:59:59'}}this.startPickerOptions.selectableRange = this.finalStartSelectableRangethis.$forceUpdate()}},endDate: {handler(newVal) {if (!newVal) {return}let today = new Date()if (this.changeType(newVal) === this.changeType(today)) {if (this.startDate && this.changeType(newVal) === this.changeType(today)) {this.finalEndSelectableRange = this.getHourChange(this.startDate) + ':' + this.getMinutesChange(this.startDate) + ':00 - 23:59:59'} else {this.finalEndSelectableRange = '00:00:00 - 23:59:59'}} else {if (this.changeType(newVal) === this.changeType(this.startDate)) {this.finalEndSelectableRange = this.getHourChange(this.startDate) + ':' + this.getMinutesChange(this.startDate) + ':00 - 23:59:59'} else {this.finalEndSelectableRange = '00:00:00 - 23:59:59'}}this.endPickerOptions.selectableRange = this.finalEndSelectableRangethis.$forceUpdate()}}},mounted() {// 处理初始数据this.filterDate()},created() {},methods: {/*** -----------------------------------------------------组件方法-----------------------------------------------------------** 控制时间段禁用的主要逻辑是在时间选择器的focus方法中处理*/// 开始时间组件的focus方法startFocus() {// 1. 将多个时间段按时间正序排序this.filterDataList.sort(function(a, b) {// sort按时间正序排序return Date.parse(a.dayEnd) - Date.parse(b.dayEnd)})// 2. 判断是否存在结束日期let today = this.changeType(new Date()) // 记录当前日期,格式为yyyy-MM-dd// 存在结束日期if (this.endDate) {let changeEndDate = this.changeType(this.endDate) // 转为yyyy-MM-dd格式,用做字符串大小对比console.log('处理后的日期:', changeEndDate, today)if (this.filterDataList.length === 0) {// 时间段数组无数据,不需做处理} else {for (let i = 0; i < this.filterDataList.length; i++) {if (this.filterDataList.length === 1) {// 长度为1时if (changeEndDate > this.filterDataList[0].dayEnd) {// 结束时间大于这个时间段的结束时间this.limitedStartDate = this.filterDataList[0].dayStart} else {this.limitedStartDate = today}} else {// 长度大于1时// 结束时间大于等于当前时间段的结束时间并且结束时间小于等于下一个时间段的结束时间if (i < this.filterDataList.length - 1 && changeEndDate >= this.filterDataList[i].dayEnd && changeEndDate <= this.filterDataList[i + 1].dayStart) {this.limitedStartDate = this.filterDataList[i].dayEnd} else if (changeEndDate < this.filterDataList[0].dayStart) {// 结束时间在第一个时间段之前this.limitedStartDate = today} else if (changeEndDate > this.filterDataList[this.filterDataList.length - 1].dayEnd) {// 结束时间在最后一个时间段之后this.limitedStartDate = this.filterDataList[this.filterDataList.length - 1].dayEnd}}}}// 3. 遍历过滤后的数据并禁用相应的时间段this.startPickerOptions = Object.assign({}, this.startPickerOptions, {disabledDate: (time) => {let disable // 定义禁用字段let finalStart = '' // 定义临时开始日期if (today < changeEndDate) {if (today < this.limitedStartDate) {disable = time < new Date(this.limitedStartDate)finalStart = this.limitedStartDate} else {disable = time < new Date(today).getTime() - 8.64e7 // 减去一天8.64e7,使得可以选择和结束日期同一天finalStart = today}} else {disable = time < new Date(today).getTime() - 8.64e7 // 减去一天8.64e7finalStart = today}// 此数组存储的为根据结束时间限定的最终的禁用时间段let tempList = [{dayStart: finalStart,dayEnd: changeEndDate}]tempList.forEach(item => {disable = disable || (time.getTime() > new Date(item.dayEnd).getTime())})return disable},selectableRange: this.finalStartSelectableRange})} else {// 结束时间为空,遍历过滤后的数据并禁用相应的时间段this.startPickerOptions = Object.assign({}, this.startPickerOptions, {disabledDate: (time) => {let disable = time < new Date(new Date().setHours(0, 0, 0, 0)) // 获取当天0点this.filterDataList.forEach(item => {disable = disable || (time.getTime() > new Date(item.dayStart).getTime() - 8.64e7 && time.getTime() < new Date(item.dayEnd).getTime()) // 减去一天8.64e7})return disable},selectableRange: this.finalStartSelectableRange})}},// 开始时间组件的change方法,只要选中的值改变,不管是否点击了确定按钮(关闭弹窗),都会触发startValueChangeEvent(value) {console.log('开始时间的值', value)this.startDate = value},// 结束时间组件的focus方法endFocus() {// 1. 将多个时间段按时间逆序排序this.filterDataList.sort(function(a, b) {// sort按时间逆序排序return Date.parse(a.dayStart) - Date.parse(b.dayStart)})// 2. 判断是否存在开始日期let today = this.changeType(new Date()) // 记录当前日期,格式为yyyy-MM-ddif (this.startDate) {let changeStartDate = this.changeType(this.startDate) // 转为yyyy-MM-dd格式,用做字符串大小对比console.log('处理后的日期:', changeStartDate, today)if (this.filterDataList.length === 0) {// 时间段数组无数据,不需做处理} else {for (let i = 0; i < this.filterDataList.length; i++) {if (this.filterDataList.length === 1) {// 长度为1时if (changeStartDate > this.filterDataList[0].dayEnd) {// 开始时间大于这个时间段的结束时间this.limitedEndDate = ''} else {this.limitedEndDate = this.filterDataList[0].dayStart}} else {// 长度大于1时// 开始时间大于等于当前时间段的开始时间并且开始时间小于等于下一个时间段的开始时间if (i < this.filterDataList.length - 1 && changeStartDate >= this.filterDataList[i].dayEnd && changeStartDate <= this.filterDataList[i + 1].dayStart) {this.limitedEndDate = this.filterDataList[i + 1].dayStart} else if (changeStartDate < this.filterDataList[0].dayStart) {// 开始时间在第一个时间段之前this.limitedEndDate = this.filterDataList[0].dayStart} else if (changeStartDate > this.filterDataList[this.filterDataList.length - 1].dayEnd) {// 开始时间在最后一个时间段之后this.limitedEndDate = ''}}}}// 3. 遍历过滤后的数据并禁用相应的时间段this.endPickerOptions = Object.assign({}, this.endPickerOptions, {disabledDate: (time) => {let disable // 定义禁用字段if (changeStartDate) {// 结束日期可与开始日期为同一天disable = time.getTime() < new Date(Date.parse(changeStartDate)).getTime() - 8.64e7} else {disable = time.getTime() < new Date(today).getTime() - 8.64e7}let tempList = [{dayStart: changeStartDate,dayEnd: this.limitedEndDate}]tempList.forEach(item => {if (!item.dayEnd) {} else {disable = disable || (time.getTime() > new Date(Date.parse(item.dayEnd)).getTime() - 8.64e7) // 减去一天8.64e7}})return disable},selectableRange: this.finalEndSelectableRange})} else {// 无开始时间this.endPickerOptions = Object.assign({}, this.endPickerOptions, {disabledDate: (time) => {let disable = time < new Date(new Date().setHours(0, 0, 0, 0)) // 获取当天0点this.filterDataList.forEach(item => {disable = disable || (time.getTime() > new Date(item.dayStart).getTime() - 8.64e7 && time.getTime() < new Date(item.dayEnd).getTime())})return disable},selectableRange: this.finalEndSelectableRange})}},// 结束时间组件的change方法endValueChangeEvent(value) {console.log('结束时间的值:', value)this.endDate = value},/*** ---------------------------------------------------按钮相关方法-----------------------------------------------------------*/// 新增时间段addDateRange() {if (this.startDate && this.endDate) {this.dateList.push({dayStart: this.startDate,dayEnd: this.endDate})// 处理数据this.filterDate()this.$message({type: 'success',message: '时间段添加成功!'})} else {this.$message({type: 'warning',message: '数据有误,请重新选择时间!'})}},// 数据过滤 返回数据正常的数据,此方法可用作过滤接口返回数据filterDate() {this.filterDataList = []// 对初始数据进行深拷贝,避免数据污染let tempArr = this.deepCopy(this.dateList)tempArr.forEach(item => {if (item.dayStart && item.dayStart !== 'NaN-NaN-NaN' && item.dayEnd && item.dayEnd !== 'NaN-NaN-NaN') {item.dayStart = this.changeType(item.dayStart)item.dayEnd = this.changeType(item.dayEnd)this.filterDataList.push(item)}})},/*** ------------------------------------------------工具函数--------------------------------------------------------*/// 转换时间格式,type可不传 此方法可继续拆分实现获取单独的年、月、日、时、分、秒 此处简略changeType(val, type) {let date = new Date(Date.parse(val))let Y = date.getFullYear()let M = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : (date.getMonth() + 1)let D = date.getDate() < 10 ? ('0' + date.getDate()) : date.getDate()val = Y + '-' + M + '-' + Dif (type === 'yyyy-MM-dd HH:mm') {let h = (date.getHours() < 10 ? '0' + (date.getHours()) : date.getHours())let m = (date.getMinutes() < 10 ? '0' + (date.getMinutes()) : date.getMinutes())val = val + ' ' + h + ':' + m}return val},// 获取单独的小时(24小时制)getHourChange(val) {let date = new Date(Date.parse(val))return date.getHours() < 10 ? '0' + (date.getHours()) : date.getHours()},// 获取单独的分钟getMinutesChange(val) {let date = new Date(Date.parse(val))return date.getMinutes() < 10 ? '0' + (date.getMinutes()) : date.getMinutes()},// 深拷贝deepCopy (obj) {const result = Array.isArray(obj) ? [] : {}for (var key in obj) {if (obj.hasOwnProperty(key)) {if (typeof obj[key] === 'object' && obj[key] !== null) {if (obj[key] instanceof RegExp) {result[key] = obj[key]} else {result[key] = this.deepCopy(obj[key]) // 递归复制}} else {result[key] = obj[key]}}}return result}}
}</script><style lang="scss" scoped>
.origin-table {height: 400px;overflow: auto;
}
.handled-table {height: 400px;overflow: auto;
}
.my-start-date {width: 40%;margin: 10px;/* 修改被禁用的时间背景色,需注意会不会影响全局样式 *//deep/ .el-date-table td.disabled div {background-color: pink !important;}
}
.my-end-date {width: 40%;margin: 10px;
}
</style>
最终的效果如下
完整代码文件
时间选择器实现禁用多个时间段(只精确到年月日)并能动态更新禁用时间段
时间选择器实现精确到时分禁用多个时间段并能动态更新禁用时间段
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!