vue3、vant4、ts封装时间段组件(开始时间-结束时间)

257 阅读6分钟

描述:vue3、vant4、ts封装时间段组件(开始时间-结束时间)

效果:

9a5f9d136ec69e5c662ddb1788efac4.png

代码:(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]);

有问题,可及时的沟通