描述:vue3、vant4、ts封装时间段组件(开始时间-结束时间)
效果:
代码:(ref、defineProps 等等的使用,我这面使用了 自动导入API插件 unplugin-auto-import,可用 可不用自己选择,若是报错可在组件中自行引入)
<template>
<span @click="valueClick" class="time_value">{{ valueStr }}</span>
<van-icon name="notes-o" color="#333333" size="18" />
<van-popup v-model:show="popupVisible" round position="bottom" @close="onPopupClose">
<van-picker v-model="selectedValues" :columns="columns" @change="onChange" @confirm="onConfirm"
@cancel="onPopupClose" />
</van-popup>
</template>
<script setup lang="ts">
import dayjs from "dayjs";
import { showFailToast } from 'vant';
const emit = defineEmits(['confirm']);
// props
const props = defineProps({
// 数据
valueList: {
type: Array,
required: true,
default: () => {
return [dayjs(new Date()).format('YYYY-MM-DD'), dayjs(new Date()).format('YYYY-MM-DD')]
}
},
// 范围的 最小时间
minDate: {
type: Date,
default: new Date(2000, 1, 1),
required: true,
},
// 范围的 最大时间
maxDate: {
type: Date,
default: new Date(),
required: true,
},
});
// 页面数据展示
const valueStr = ref(props.valueList[0] + '~' + props.valueList[1]);
let minYearValueList = (props.valueList[0] as string).split('-');
let minYearValue = minYearValueList[0];
let minMounthValue = minYearValueList[1];
let minDateValue = minYearValueList[2];
let maxYearValueList = (props.valueList[1] as string).split('-');
let maxYearValue = maxYearValueList[0];
let maxMounthValue = maxYearValueList[1];
let maxDateValue = maxYearValueList[2];
//picker 数据返显
let years1 = ref([] as Array<{ text: string; value: string }>);
let months1 = ref([] as Array<{ text: string; value: string }>);
let days1 = ref([] as Array<{ text: string; value: string }>);
for (let i = 1; i <= 12; i++) {
months1.value.push({ text: i.toString().padStart(2, '0'), value: i.toString().padStart(2, '0') });
}
for (let i = 1; i <= 31; i++) {
days1.value.push({ text: i.toString().padStart(2, '0'), value: i.toString().padStart(2, '0') });
}
// 数据限定范围 最小值和最大值
const minYear = ref(props.minDate.getFullYear());
const minMounth = ref(props.minDate.getMonth());
const minDate = ref(props.minDate.getDate());
const maxYear = ref(props.maxDate.getFullYear());
const maxMounth = ref(props.maxDate.getMonth() + 1);
const maxDate = ref(props.maxDate.getDate());
const minTwoYear = ref(props.minDate.getFullYear());
const minTwoMounth = ref(props.minDate.getMonth());
const minTwoDate = ref(props.minDate.getDate());
let i = 0;
while (i < maxYear.value - minYear.value + 1) {
years1.value.unshift({ text: maxYear.value - i + '', value: maxYear.value - i + '' });
i++;
}
let years2 = ref([] as Array<{ text: string; value: string }>);
let months2 = ref([] as Array<{ text: string; value: string }>);
let days2 = ref([] as Array<{ text: string; value: string }>);
for (let i = 1; i <= 12; i++) {
months2.value.push({ text: i.toString().padStart(2, '0'), value: i.toString().padStart(2, '0') });
}
for (let i = 1; i <= 31; i++) {
days2.value.push({ text: i.toString().padStart(2, '0'), value: i.toString().padStart(2, '0') });
}
let k = 0;
while (k < maxYear.value - minYear.value + 1) {
years2.value.unshift({ text: maxYear.value - k + '', value: maxYear.value - k + '' });
k++;
}
const columns = ref([
years1.value, months1.value, days1.value, [{ text: '~', value: '~' }], years2.value, months2.value, days2.value
]);
const selectedValues = ref<string[]>([]);
selectedValues.value = [minYearValue, minMounthValue, minDateValue, '~', maxYearValue, maxMounthValue, maxDateValue]
const changeFlag = ref(false);
const changeFlag1 = ref(false);
const onChange = (picker: any) => {
console.log(picker)
if (picker.columnIndex == 0) {
// 如果 最小的年份 等于 最大的月份
if (picker.selectedValues[0] == minYear.value && picker.selectedValues[0] == maxYear.value) {
// 限制月份的数据
columns.value[1] = generateMonthArrayInRange(minMounth.value, maxMounth.value)
minMounthValue = columns.value[1][0].value;
if (Number(minMounthValue) == minMounth.value && Number(minMounthValue) == maxMounth.value) {
// 限制日期的数据
columns.value[2] = generateDaysArrayInRange(minMounth.value, minDate.value, maxDate.value)
} else if (Number(minMounthValue) == minMounth.value) {
// 限制日期的数据
columns.value[2] = generateDaysArray(picker.selectedValues[0], minMounth.value, Number(minDate.value))
} else if (Number(minMounthValue) == maxMounth.value) {
// 限制日期的数据
columns.value[2] = generateDaysArrayWithEndDate(minMounth.value, maxDate.value)
}
} else if (picker.selectedValues[0] == minYear.value) {
// 如果为最小的年
// 限制月份的数据
columns.value[1] = generateMonthArray(minMounth.value)
minMounthValue = columns.value[1][0].value;
if (Number(minMounthValue) == minMounth.value && Number(minMounthValue) == maxMounth.value) {
// 限制日期的数据
columns.value[2] = generateDaysArrayInRange(minMounth.value, minDate.value, maxDate.value)
} else if (Number(minMounthValue) == minMounth.value) {
// 限制日期的数据
columns.value[2] = generateDaysArray(picker.selectedValues[0], minMounth.value, Number(minDate.value))
} else if (Number(minMounthValue) == maxMounth.value) {
// 限制日期的数据
columns.value[2] = generateDaysArrayWithEndDate(minMounth.value, maxDate.value)
}
} else if (picker.selectedValues[0] == maxYear.value) {
// 如果为最最大的年
columns.value[1] = generateMaxMonthArray(maxMounth.value)
minMounthValue = columns.value[1][0].value;
if (Number(minMounthValue) == minMounth.value && Number(minMounthValue) == maxMounth.value) {
// 限制日期的数据
columns.value[2] = generateDaysArrayInRange(minMounth.value, minDate.value, maxDate.value)
} else if (Number(minMounthValue) == minMounth.value) {
// 限制日期的数据
columns.value[2] = generateDaysArray(picker.selectedValues[0], minMounth.value, Number(minDate.value))
} else if (Number(minMounthValue) == maxMounth.value) {
// 限制日期的数据
columns.value[2] = generateDaysArrayWithEndDate(minMounth.value, maxDate.value)
}
} else {
columns.value[1] = months1.value
columns.value[2] = generateDaysArrayForMonth(picker.selectedValues[0], picker.selectedValues[1])
}
minYearValue = picker.selectedValues[0];
// 判断新生成的数组中有没有原有的值 若是有则不变 若是没有赋值数组中的第一个值
let flag = columns.value[2].some(item => item.value === picker.selectedValues[2])
if (flag) {
minDateValue = picker.selectedValues[2]
} else {
minDateValue = columns.value[2][0].value;
}
} else if (picker.columnIndex == 1) {
// 判断月份 最小值 和 最大值 相同
if (picker.selectedValues[1] == minMounth.value && picker.selectedValues[1] == maxMounth.value) {
// 限制日期的数据
columns.value[2] = generateDaysArrayInRange(minMounth.value, minDate.value, maxDate.value)
} else if (picker.selectedValues[1] == minMounth.value) {
// 限制日期的数据
columns.value[2] = generateDaysArray(picker.selectedValues[0], minMounth.value, Number(minDate.value))
} else if (picker.selectedValues[1] == maxMounth.value) {
if (picker.selectedValues[0] == minYear.value && picker.selectedValues[0] == maxYear.value) {
// 限制日期的数据
columns.value[2] = generateDaysArrayInRange(minMounth.value, minDate.value, maxDate.value)
} else if (picker.selectedValues[0] == minYear.value) {
// 限制日期的数据
columns.value[2] = generateDaysArrayInRange(minMounth.value, minDate.value, maxDate.value)
} else if (picker.selectedValues[0] == maxYear.value) {
// 限制日期的数据
columns.value[2] = generateDaysArrayInRange(minMounth.value, minDate.value, maxDate.value)
} else {
columns.value[2] = generateDaysArrayForMonth(picker.selectedValues[0], picker.selectedValues[1])
}
} else {
// 限制日期的数据
columns.value[2] = generateDaysArrayForMonth(picker.selectedValues[0], picker.selectedValues[1])
}
minMounthValue = picker.selectedValues[1];
// 判断新生成的数组中有没有原有的值 若是有则不变 若是没有赋值数组中的第一个值
let flag = columns.value[2].some(item => item.value === picker.selectedValues[2])
if (flag) {
minDateValue = picker.selectedValues[2]
} else {
minDateValue = columns.value[2][0].value;
}
} else if (picker.columnIndex == 4) {
// 如果 最小的年份 等于 最大的月份
if (picker.selectedValues[4] == minTwoYear.value && picker.selectedValues[4] == maxYear.value) {
// 限制月份的数据
columns.value[5] = generateMonthArrayInRange(minTwoMounth.value, maxMounth.value)
maxMounthValue = columns.value[5][0].value;
if (Number(maxMounthValue) == minTwoMounth.value && Number(maxMounthValue) == maxMounth.value) {
// 限制日期的数据
columns.value[6] = generateDaysArrayInRange(minTwoMounth.value, minTwoDate.value, maxDate.value)
} else if (Number(maxMounthValue) == minTwoMounth.value) {
// 限制日期的数据
columns.value[6] = generateDaysArray(picker.selectedValues[4], minTwoMounth.value, Number(minTwoDate.value))
} else if (Number(maxMounthValue) == maxMounth.value) {
// 限制日期的数据
columns.value[6] = generateDaysArrayWithEndDate(minTwoMounth.value, maxDate.value)
}
} else if (picker.selectedValues[4] == minTwoYear.value) {
// 如果为最小的年
// 限制月份的数据
columns.value[5] = generateMonthArray(minTwoMounth.value)
maxMounthValue = columns.value[5][0].value;
if (Number(maxMounthValue) == minTwoMounth.value && Number(maxMounthValue) == maxMounth.value) {
// 限制日期的数据
columns.value[6] = generateDaysArrayInRange(minTwoMounth.value, minTwoDate.value, maxDate.value)
} else if (Number(maxMounthValue) == minTwoMounth.value) {
// 限制日期的数据
columns.value[6] = generateDaysArray(picker.selectedValues[4], minTwoMounth.value, Number(minTwoDate.value))
} else if (Number(maxMounthValue) == maxMounth.value) {
// 限制日期的数据
columns.value[6] = generateDaysArrayWithEndDate(minTwoMounth.value, maxDate.value)
}
} else if (picker.selectedValues[4] == maxYear.value) {
// 如果为最最大的年
columns.value[5] = generateMaxMonthArray(maxMounth.value)
maxMounthValue = columns.value[5][0].value;
if (Number(maxMounthValue) == minTwoMounth.value && Number(maxMounthValue) == maxMounth.value) {
// 限制日期的数据
columns.value[6] = generateDaysArrayInRange(minTwoMounth.value, minTwoDate.value, maxDate.value)
} else if (Number(maxMounthValue) == minTwoMounth.value) {
// 限制日期的数据
columns.value[6] = generateDaysArray(picker.selectedValues[4], minTwoMounth.value, Number(minTwoDate.value))
} else if (Number(maxMounthValue) == maxMounth.value) {
// 限制日期的数据
columns.value[6] = generateDaysArrayWithEndDate(minTwoMounth.value, maxDate.value)
}
} else {
columns.value[5] = months1.value
columns.value[6] = generateDaysArrayForMonth(picker.selectedValues[4], picker.selectedValues[5])
}
maxYearValue = picker.selectedValues[4];
// 判断新生成的数组中有没有原有的值 若是有则不变 若是没有赋值数组中的第一个值
let flag = columns.value[6].some(item => item.value === picker.selectedValues[6])
if (flag) {
maxDateValue = picker.selectedValues[6]
} else {
maxDateValue = columns.value[6][0].value;
}
} else if (picker.columnIndex == 5) {
// 判断月份 最小值 和 最大值 相同
// minTwoYear minTwoMounth minTwoDate
if (picker.selectedValues[5] == minTwoMounth.value && picker.selectedValues[5] == maxMounth.value) {
// 限制日期的数据
columns.value[6] = generateDaysArrayInRange(minTwoMounth.value, minTwoDate.value, maxDate.value)
} else if (picker.selectedValues[5] == minTwoMounth.value) {
// 限制日期的数据
columns.value[6] = generateDaysArray(picker.selectedValues[4], minTwoMounth.value, Number(minTwoDate.value))
} else if (picker.selectedValues[5] == maxMounth.value) {
if (picker.selectedValues[4] == minYear.value && picker.selectedValues[4] == maxYear.value) {
// 限制日期的数据
columns.value[6] = generateDaysArrayInRange(minTwoMounth.value, minTwoDate.value, maxDate.value)
} else if (picker.selectedValues[4] == minYear.value) {
// 限制日期的数据
columns.value[6] = generateDaysArrayInRange(minTwoMounth.value, minTwoDate.value, maxDate.value)
} else if (picker.selectedValues[4] == maxYear.value) {
// 限制日期的数据
columns.value[6] = generateDaysArrayInRange(minTwoMounth.value, minTwoDate.value, maxDate.value)
} else {
columns.value[6] = generateDaysArrayForMonth(picker.selectedValues[0], picker.selectedValues[1])
}
} else {
// 限制日期的数据
columns.value[6] = generateDaysArrayForMonth(picker.selectedValues[4], picker.selectedValues[5])
}
maxMounthValue = picker.selectedValues[5];
// 判断新生成的数组中有没有原有的值 若是有则不变 若是没有赋值数组中的第一个值
let flag = columns.value[6].some(item => item.value === picker.selectedValues[6])
if (flag) {
maxDateValue = picker.selectedValues[6]
} else {
maxDateValue = columns.value[6][0].value;
}
}
//判断是否是首次 首次为false 赋值默认的值 为true时 天的数据为选中的值
//统一的更改selectedValues 用于同步组件和页面中的值
if (changeFlag.value && changeFlag1.value) {
if (picker.columnIndex == 2) {
minDateValue = picker.selectedValues[2]
}
if (picker.columnIndex == 6) {
maxDateValue = picker.selectedValues[6]
}
selectedValues.value = [minYearValue, minMounthValue, minDateValue, '~', maxYearValue, maxMounthValue, maxDateValue]
} else {
selectedValues.value = picker.selectedValues
changeFlag.value = true;
changeFlag1.value = true;
}
};
nextTick(() => {
changeFlag.value = false
onChange({
columnIndex: 0,
selectedValues: [minYearValue, minMounthValue, minDateValue, '~', maxYearValue, maxMounthValue, maxDateValue]
})
changeFlag1.value = false
onChange({
columnIndex: 4,
selectedValues: [minYearValue, minMounthValue, minDateValue, '~', maxYearValue, maxMounthValue, maxDateValue]
})
})
//控制Popup是否展示
let popupVisible = ref(false);
//Popup的关闭时间
const onPopupClose = () => {
popupVisible.value = false;
}
// 确认
const onConfirm = () => {
// 形如 ['2001-02-23', '2024-01-29'];
let valueList = [selectedValues.value[0] + '-' + selectedValues.value[1] + '-' + selectedValues.value[2], selectedValues.value[4] + '-' + selectedValues.value[5] + '-' + selectedValues.value[6]]
let timer01 = (new Date(valueList[0])).getTime();
let timer02 = (new Date(valueList[1])).getTime();
if (timer01 > timer02) {
showFailToast('开始时间不能晚于结束时间');
return;
}
popupVisible.value = false;
let obg = {
selectedValues: selectedValues.value,
valueList: valueList
}
valueStr.value = valueList[0] + '~' + valueList[1]
emit('confirm', obg)
}
//点击时间段出现弹窗
const valueClick = () => {
popupVisible.value = true;
}
// 输入最小月份 返回月份数组
const generateMonthArray = (startMonth: number) => {
return Array.from({ length: 12 - startMonth + 1 }, (_, index) => {
const month = startMonth + index;
return { text: `${month.toString().padStart(2, '0')}`, value: `${month.toString().padStart(2, '0')}` };
});
}
// 输入最大月份 返回月份数组
const generateMaxMonthArray = (maxMonth: number): { text: string; value: string }[] => {
return Array.from({ length: maxMonth }, (_, index) => {
const month = index + 1;
return { text: `${month.toString().padStart(2, '0')}`, value: `${month.toString().padStart(2, '0')}` };
});
};
// 输入最小月份、最大月份 返回月份数组
const generateMonthArrayInRange = (minMonth: number, maxMonth: number): { text: string; value: string }[] => {
const monthsArray: { text: string; value: string }[] = Array.from({ length: maxMonth - minMonth + 1 }, (_, index) => {
const month = minMonth + index;
return { text: `${month.toString().padStart(2, '0')}`, value: `${month.toString().padStart(2, '0')}` };
});
return monthsArray;
};
// 输入年 月 开始日期 返回日期的数组
const generateDaysArray = (year: number, month: number, startDay: number): { text: string; value: string }[] => {
const daysInMonth = new Date(year, month, 0).getDate();
const daysArray: { text: string; value: string }[] = Array.from({ length: daysInMonth }, (_, index) => {
const day = index + 1;
if (day >= startDay) {
return { text: day.toString().padStart(2, '0'), value: day.toString().padStart(2, '0') };
}
}).filter((item): item is { text: string; value: string } => Boolean(item));
return daysArray;
};
// 输入月份和结束日期 返回日期的数组
const generateDaysArrayWithEndDate = (month: number, endDay: number): { text: string; value: string }[] => {
const daysInMonth = new Date(new Date().getFullYear(), month, 0).getDate();
const daysArray: { text: string; value: string }[] = Array.from({ length: daysInMonth }, (_, index) => {
const day = index + 1;
return { text: day.toString().padStart(2, '0'), value: day.toString().padStart(2, '0') };
}).filter(day => Number(day.value) <= endDay);
return daysArray;
};
// 输入月份 、起始日期 、结束日期 返回日期的数组
const generateDaysArrayInRange = (month: number, startDay: number, endDay: number): { text: string; value: string }[] => {
const daysInMonth = new Date(new Date().getFullYear(), month, 0).getDate();
const daysArray: { text: string; value: string }[] = Array.from({ length: daysInMonth }, (_, index) => {
const day = index + 1;
return { text: day.toString().padStart(2, '0'), value: day.toString().padStart(2, '0') };
}).filter(day => Number(day.value) >= startDay && Number(day.value) <= endDay);
return daysArray;
};
// 输入任意的月份 返回日期的数组
const generateDaysArrayForMonth = (year: number, month: number): { text: string; value: string }[] => {
const daysInMonth = new Date(year, month, 0).getDate();
const daysArray: { text: string; value: string }[] = Array.from({ length: daysInMonth }, (_, index) => {
const day = index + 1;
return { text: day.toString().padStart(2, '0'), value: day.toString().padStart(2, '0') };
});
return daysArray;
};
</script>
<style scoped lang="less">
.time_value {
font-size: 16px;
color: #666666;
margin-right: 5px;
}
</style>
使用:
<TimeRangePicker :valueList="valueList" :min-date="minDate" :max-date="maxDate" @confirm="onConfirm">
</TimeRangePicker>
//根据组件的问题进行改变引用位置
import TimeRangePicker from '@/components/TimeRangePicker/TimeRangePicker.vue';
// 我这面的需求默认展示当前时间前七天
const minDate: Date = new Date(2015, 1, 1);
const maxDate: Date = new Date();
const yesterday = new Date()
yesterday.setDate(yesterday.getDate() - 6) // 获取七天前的日期
let startDate = ref(dayjs(yesterday).format('YYYY-MM-DD')).value
let endDate = ref(dayjs(new Date()).format('YYYY-MM-DD')).value
let valueList = ref([startDate, endDate]);
有问题,可及时的沟通