由于vant的日期选择器无法自定义添加长期选项,故对vant的选择器进行二次封装
<template>
<van-popup @open="setCurDate" v-model:show="show" positio="bottom" teleport="#app">
<van-picker
v-model="current"
:title="title"
ref="picker"
:columns="datas"
:columns-fields-names="{ value: 'text' }"
@click-option="onChange"
@confirm="confirmDate"
@cancel="closePicker"
/>
</van-popup>
</template>
<script lang="ts" setup>
import { ref, computed, watch } from 'vue'
interface IProps {
modelValue: boolean
selDate?: string
title?: string
// 日期分隔符
splitStr?: string
}
const props = withDefaults(defineProps<IProps>(), {
title: '请选择日期',
splitStr: '.',
})
const datas = ref<any[]>([])
const picker = ref<any>(null)
const monthArr = ref(['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'])
const emits = defineEmits(['update:modelValue', 'confirmIDCertDate'])
const show = computed({
get() {
return props.modelValue
},
set(newVal: any) {
emits('update:modelValue', newVal)
},
})
const current = ref<any[]>([])
/** 回显传入的时间 */
const setCurrent = () => {
if (props.selDate) {
if (props.selDate === '长期') {
return [props.selDate]
}
return props.selDate.split(props.splitStr)
}
// 没有传入时间则默认选中当前时间
return [
new Date().getFullYear().toString(),
(new Date().getMonth() + 1).toString().padStart(2, '0'),
new Date().getDate().toString().padStart(2, '0'),
]
}
/** 打开选择器设置日期 */
const setCurDate = () => {
current.value = setCurrent()
}
/** 修改日期 */
const confirmDate = () => {
emits(
'confirmIDCertDate',
current.value?.[0] === '长期' ? '长期' : current.value.join(props.splitStr),
)
}
/** 关闭弹窗 */
const closePicker = () => {
emits('update:modelValue', false)
}
/** 获取不同月份的天数 */
const getDays = (year: number, month: number) => {
const daysNumber = new Date(year, month, 0).getDate()
const daysNumberArr = []
for (let i = 1; i <= daysNumber; i += 1) {
// 少于两位补0
daysNumberArr.push(i.toString().padStart(2, '0'))
}
return daysNumberArr
}
/** 格式化数组 */
const formatArr = (arr: any) => {
return arr.map((item: any) => ({ text: item }))
}
const setYears = () => {
const date = new Date(Number(current.value[0]), Number(current.value[1]), 0)
let year = new Date().getFullYear()
const yearsArr = []
const daysArr = getDays(date.getFullYear(), date.getMonth() + 1)
// 可选时间,20年前后
year -= 20
for (let i = 0; i <= 40; i += 1) {
yearsArr.push(year.toString())
year += 1
}
// 增加长期选项
yearsArr.push('长期')
// 初始化选择器选项
datas.value = [formatArr(yearsArr), formatArr(monthArr.value), formatArr(daysArr)]
}
/** 选中项发生变化时执行 */
const onChange = (values: any) => {
// 判断选中项是不是长期,不是长期时动态更改第三列的值
current.value = values?.selectedValues
}
/** 监听:当current选中长期时,删除多余的两列,只留下长期列,反之则初始化两外两列 */
watch(
() => current.value,
() => {
if (current.value[0] === '长期') {
let year = new Date().getFullYear()
const yearsArr = []
year -= 20
for (let i = 0; i <= 40; i += 1) {
yearsArr.push(year.toString())
year += 1
}
// 增加长期选项
yearsArr.push('长期')
datas.value = [formatArr(yearsArr)]
} else {
setYears()
}
},
)
</script>
使用方式
<identity-date-select
v-model="isShowDatePicker"
:selDate="selDate"
title="请选择证件有效期"
splitStr="-"
@confirmIDCertDate="confirmIDCertDate"
/ >
const isShowDatePicker = ref(false);
const selDate = ref('2025-03-07');
const confirmIDCertDate = (date: string) => {
isShowDatePicker.value = false;
selDate.value = date;
}