vant封装身份证有效期日期选择器并添加长期有效选项(vant+ts+vue3)

333 阅读2分钟

由于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;
}