vant实现自定义日期时间选择器(年月日时分秒)

 更新时间:2025年12月25日 08:26:17   作者:无心使然云中漫步  
使用vant作为UI组件时,需要一个日期时间选择器,vant中有Dateicker和TimePicker,可以将两个组件组合封装使用,下面就来详细的介绍一下

1 背景

使用vant作为UI组件时,需要一个日期时间选择器,vant中有Dateicker和TimePicker,可以将两个组件组合封装使用,但是处理传入参数和传出参数稍显麻烦,所以使用Picker封装一个简单的日期时间选择器

2 要求

  • 可以传入初始值
  • 可以选择年,年月,年月日,年月日时,年月日时分,年月日时分秒
  • 可以限定选择的最大日期和最小日期

3 实现

// DateTimePicker.vue
<template>
    <van-picker
        ref="picker"
        title="请选择时间"
        :columns="columns"
        @change="handleChange"
        @cancel="handleCancel"
        @confirm="handleConfirm"
        v-model="values"
    />
</template>
<script setup lang="ts">
const props = defineProps({
    // 显示的列数量共6列(年月日时分秒)
    columnCount: {
        type: Number,
        default: 6,
    },
    // 可以选择的最小日期
    minDate: {
        type: Date,
        default: new Date(new Date().getFullYear() - 10, 1, 1, 0, 0, 0),
    },
    // 可以选择的最大日期
    maxDate: {
        type: Date,
        default: new Date(new Date().getFullYear() + 10, 11, 31, 23, 59, 59),
    },
});

const values = defineModel({
    get(val) {
        let param = val;
        if (Array.isArray(param)) {
            if (param.length > 0) {
                return param.map(i => i.toString().padStart(2, '0'));
            }
            param = new Date();
        } else if (!param) {
            param = new Date();
        }
        const date = new Date(param);
        const Y = date.getFullYear().toString();
        const M = (date.getMonth() + 1).toString().padStart(2, '0'); //实际月份
        const D = date.getDate().toString().padStart(2, '0');
        const h = date.getHours().toString().padStart(2, '0');
        const m = date.getMinutes().toString().padStart(2, '0');
        const s = date.getSeconds().toString().padStart(2, '0');

        return [Y, M, D, h, m, s];
    },
});

const columns = ref([]); //所有时间列

const maxDateArray = computed(() => getDateArray(props.maxDate));

onBeforeMount(() => {
    getColumns();
});

const getColumns = () => {
    const options = [
        {
            radix: props.maxDate.getFullYear() - props.minDate.getFullYear() + 1,
            base: props.minDate.getFullYear(),
        },
        {
            radix: 12,
            base: 1,
        },
        {
            radix: getCountDays(values.value[0], values.value[1]),
            base: 1,
        },
        {
            radix: 24,
            base: 0,
        },
        {
            radix: 60,
            base: 0,
        },
        {
            radix: 60,
            base: 0,
        },
    ].slice(0, props.columnCount);
    options.forEach((item, index) => {
        columns.value.push(fillData(index, item.radix, item.base));
    });
};

const fillData = (index, radix, baseNum = 0) => {
    return Object.keys(new Array(radix).fill()).map(item => ({
        text: (Number(item) + baseNum).toString().padStart(2, '0'),
        value: (Number(item) + baseNum).toString().padStart(2, '0'),
        disabled: Number(item) + baseNum > maxDateArray.value[index],
    }));
};

const getCountDays = (year, month) => {
    //获取某年某月最后1天
    return new Date(year, month, 0).getDate();
};

const getDateArray = param => {
    const date = new Date(param);
    const Y = date.getFullYear();
    const M = date.getMonth() + 1; //实际月份
    const D = date.getDate();
    const h = date.getHours();
    const m = date.getMinutes();
    const s = date.getSeconds();

    return [Y, M, D, h, m, s];
};

const handleChange = ({ selectedValues, columnIndex }) => {
    const dateArray = [...selectedValues].map((i, idx) => {
        if (idx == 1) {
            return Number(i) - 1;
        }
        return Number(i);
    });
    const maxDate = maxDateArray.value.map((i, idx) => {
        if (idx == 1) {
            return Number(i) - 1;
        }
        return i;
    });

    if (columnIndex <= 1 && columns.value.length > 2) {
        const lastDay = getCountDays(Number(selectedValues[0]), Number(selectedValues[1]));
        columns.value[2] = fillData(2, lastDay, 1);

        if (lastDay < Number(selectedValues[2])) {
            //切换年列或者月列时,因为每月的天可能不同,所以天列需要重置
            values.value = values.value
                .map((item, idx) => {
                    if (idx === 2) {
                        return lastDay.toString();
                    }
                    return item;
                })
                .slice(0, props.columnCount);
        }
    }

    if (
        new Date(...dateArray.slice(0, columnIndex + 1)).getTime() <
        new Date(...maxDate.slice(0, columnIndex + 1)).getTime()
    ) {
        for (let i = columnIndex + 1; i < columns.value.length; i++) {
            columns.value[i].forEach(k => {
                k.disabled = false;
            });
        }
    } else {
        for (let i = columnIndex + 1; i < columns.value.length; i++) {
            columns.value[i].forEach(k => {
                if (Number(k.value) > maxDateArray.value[i]) {
                    k.disabled = true;
                }
            });
        }
        if (new Date(...dateArray).getTime() > new Date(...maxDate).getTime()) {
            values.value = maxDateArray.value.slice(0, props.columnCount);
        }
    }
};

const handleCancel = () => {
    emit('cancel');
};

const handleConfirm = ({ selectedValues }) => {
    emit(
        'confirm',
        (selectedValues.slice(0, 3).join('-') + ' ' + selectedValues.slice(3).join(':')).trim()
    );
};

const emit = defineEmits(['confirm', 'cancel']);
</script>

// index.vue
<template>
<van-button type="primary" @click="handleClick">选择日期</van-button>
<van-popup v-model:show="showPicker" round position="bottom">
<DateTimePicker
    v-model="values"
    :maxDate="maxDate"
    @cancel="handleCancel"
    @confirm="handleConfirm"
/>
</van-popup>
</template>
<script setup lang="ts">
const maxDate = new Date();
const showPicker = ref(false);
const values = ref(['2025','12','23','12','01','12']);//设置初始日期时间
const handleConfirm = () => { 
     //点击确定的事件
     showPicker.value = false;
}

const handleCancel = () => {
    //点击取消的事件,比如关闭弹框
    showPicker.value = false;
}

const handleClick = () => {
     showPicker.value = true;
}
 </script>   

到此这篇关于vant实现自定义日期时间选择器(年月日时分秒)的文章就介绍到这了,更多相关vant 日期时间选择器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 一篇文章带你了解Vue组件的创建和使用

    一篇文章带你了解Vue组件的创建和使用

    这篇文章主要为大家介绍了Vue组件的创建和使用,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2021-12-12
  • Vue中的v-for指令不起效果的解决方法

    Vue中的v-for指令不起效果的解决方法

    今天小编就为大家分享一篇Vue中的v-for指令不起效果的解决方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-09-09
  • 详解element-ui级联菜单(城市三级联动菜单)和回显问题

    详解element-ui级联菜单(城市三级联动菜单)和回显问题

    这篇文章主要介绍了详解element-ui级联菜单(城市三级联动菜单)和回显问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-10-10
  • vue金额格式化保留两位小数的实现

    vue金额格式化保留两位小数的实现

    这篇文章主要介绍了vue金额格式化保留两位小数的实现方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-04-04
  • vue组件发布成npm包

    vue组件发布成npm包

    平常使用Vue开发时,一个项目中多个地方需要用到的相同组件通常我们会封装为一个公共组件,所以我们可以将封装好的组件打包发布至npm,本文主要介绍了vue组件发布成npm包,具有一定的参考价值,感兴趣的可以了解一下
    2024-01-01
  • vue获取后台json字符串方式

    vue获取后台json字符串方式

    这篇文章主要介绍了vue获取后台json字符串方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-04-04
  • Vue body样式修改方式

    Vue body样式修改方式

    这篇文章主要介绍了Vue body样式修改方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-01-01
  • vue添加axios,并且指定baseurl的方法

    vue添加axios,并且指定baseurl的方法

    今天小编就为大家分享一篇vue添加axios,并且指定baseurl的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-09-09
  • 100行代码实现vue表单校验功能(小白自编)

    100行代码实现vue表单校验功能(小白自编)

    这篇文章主要介绍了使用100行代码实现vue表单校验功能,本文通过实例截图给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-11-11
  • vue项目同时兼容pc和移动端的解决方式

    vue项目同时兼容pc和移动端的解决方式

    我们经常在项目中会有支持pc与手机端需求,下面这篇文章主要给大家介绍了关于vue项目同时兼容pc和移动端的解决方式,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2023-10-10

最新评论