之前写了一个时间组件,然后稍有不足,现在改进一下,具体的改进点就是,原先的时候,我选择某年某月的话,发现天,每次都是31一天。然后用选了个11月31号,接口后端拿到这个日期,不出所料的报错了,因为去年11月是没有31号的,所以今天改进一下,改进的点就是,当van-picker时间改变的时候,就检测处于哪年,哪月,然后对于相应的年月,展示正确的天数,将这个天数的数组,展示在相对应的一列即可
下面我就是完整的组件代码:
<!--
* @Description: 年月日时分秒 时间选择组件
* @FilePath: \shared\common\src\components\DateTimePicker
-->
<template>
<!-- 参数说明
/**
* |-Params[cellTitle] {String} 单元格名称 默认时间 (必传)
* |-Params[values] {String} 传入的时间值 格式为YYYY-MM-DD HH:mm:ss (必传)
* |-Params[disabled] {Boolean} 是否可被选中
* 示例:<DateTimePicker :cellTitle="'创建时间'" :values="''" @dateConfirm="" :disabled="false"/>
*/
-->
<div :class="['date-box', { edit: !disabled }]">
<van-cell
:title="cellTitle"
:is-link="!disabled"
:value="values"
@click="showPopup"
/>
</div>
<van-popup
v-model:show="data.isPicker"
position="bottom"
round
@close="closePop"
>
<van-picker
ref="picker"
v-model="data.selectedValues"
title="请选择时间"
:columns="data.columns"
@change="onChange"
@cancel="cancelOn"
@confirm="onConfirm"
>
<template #columns-top>
<div class="title" style="height: 3rem">
<span>年</span>
<span>月</span>
<span>日</span>
<span>时</span>
<span>分</span>
<span>秒</span>
</div>
</template>
</van-picker>
</van-popup>
</template>
<script setup lang="ts">
import {
reactive,
watch,
getCurrentInstance,
defineProps,
defineEmits,
ref,
Ref
} from "vue";
import { format } from "date-fns";
const values: Ref<string> = ref(""); //时间值 YYYY-MM-DD HH:mm:ss
const emits = defineEmits(["dateConfirm"]);
const customFieldName = {
text: "value",
value: "values",
children: ""
};
const data = reactive({
isPicker: false, //是否显示弹出层
columns: [], //所有时间列
selectedValues: [] //控件选择的时间值
});
const props = defineProps({
// 传入的值
values: {
type: String
},
// 单元格名称
cellTitle: {
type: String,
required: false
},
// 是否可以选中
disabled: {
type: Boolean,
required: false,
default: false
}
});
watch(
() => props.values,
val => {
if (!val) {
values.value = format(new Date(), "yyyy-MM-dd HH:mm:ss");
} else {
values.value = props.values;
}
data.columns = [];
getcolumns();
},
{
immediate: true
}
);
/**
* @description: 月份改变,获取天数
*/
function onChange(values) {
const year = parseInt(values.selectedValues[0], 10);
const month = parseInt(values.selectedValues[1], 10);
// 获取当月天数
const days = getCountDays(year, month);
const daysArray = Array.from({ length: days }, (_, index) => {
const day = index + 1;
const columnDay = day.toString().padStart(2, "0");
return { text: columnDay, value: columnDay };
});
data.columns[2] = daysArray;
}
function showPopup() {
if (!props.disabled) {
data.isPicker = true;
}
}
/**
* @description: 获取时间列
*/
function getcolumns() {
const strtime = values.value; // 传入的时间
const date = new Date(strtime.replace(/-/g, "/"));
let dateVaules = date;
if (!props.values) {
dateVaules = new Date(); //当前的时间
}
const Y = dateVaules.getFullYear();
const M = dateVaules.getMonth() + 1; // 月份是从0开始,所以+1
const D = dateVaules.getDate();
const h = dateVaules.getHours();
const m = dateVaules.getMinutes();
const s = dateVaules.getSeconds();
// 补0
const formatNumber = (num: number) => num.toString().padStart(2, "0");
const _M = formatNumber(M);
const _D = formatNumber(D);
const _h = formatNumber(h);
const _m = formatNumber(m);
const _s = formatNumber(s);
// 更新
data.selectedValues = [Y, _M, _D, _h, _m, _s];
// 年
const years = Array.from({ length: 20 }, (_, i) => ({
text: (Y - 10 + i).toString(),
value: Y - 10 + i
}));
years.defaultIndex = years.findIndex(year => year.value === Y);
data.columns.push(years);
// 月
const months = Array.from({ length: 12 }, (_, i) => ({
text: formatNumber(i + 1),
value: formatNumber(i + 1)
}));
data.columns.push(months);
// 日期列表 根据当年与当月计算天数
const days = getCountDays(Y, M);
const daysOfMonth = Array.from({ length: days }, (_, i) => ({
text: formatNumber(i + 1),
value: formatNumber(i + 1)
}));
data.columns.push(daysOfMonth);
// 时 分 秒
const hours = Array.from({ length: 24 }, (_, i) => ({
text: formatNumber(i),
value: formatNumber(i)
}));
data.columns.push(hours);
const minutes = Array.from({ length: 60 }, (_, i) => ({
text: formatNumber(i),
value: formatNumber(i)
}));
data.columns.push(minutes);
const seconds = Array.from({ length: 60 }, (_, i) => ({
text: formatNumber(i),
value: formatNumber(i)
}));
data.columns.push(seconds);
}
/**
* @description: 辅助函数 格式化数字,始终保持两位数
* @param: num
*/
function formatNumber(num: number): string {
return num.toString().padStart(2, "0");
}
/**
* @description: 获取某年某月多少天
* @param: year month
*/
function getCountDays(year, month) {
let day = new Date(year, month, 0);
return day.getDate();
}
/**
* @description: 关闭底部弹窗
* @param:
*/
function closePop() {
data.isPicker = false;
}
/**
* @description: 时间选择器关闭 值不改变并关闭弹框
* @param: selectedValues 选中的值
*/
function cancelOn({ selectedValues }) {
data.isPicker = false;
}
/**
* @description: 时间选择器确认
* @param: selectedValues 选中的时间值(Array)
*/
function onConfirm({ selectedValues }) {
let endval =
selectedValues[0] +
"-" +
selectedValues[1] +
"-" +
selectedValues[2] +
" " +
selectedValues[3] +
":" +
selectedValues[4] +
":" +
selectedValues[5];
values.value = endval;
data.isPicker = false;
emits("dateConfirm", endval);
}
</script>
<style scoped lang="less">
.date-box {
flex: 1;
:deep(.van-cell) {
padding: 0;
.van-cell__value {
color: #333;
}
}
}
.edit {
:deep(.van-cell) {
.van-cell__value {
color: #3f72e4;
}
.van-icon {
color: #3f72e4;
}
}
}
.title {
min-height: 4rem;
padding: 2rem 0;
display: flex;
justify-content: space-around;
align-items: center;
color: #323233;
font-weight: 800;
}
</style>