美文网首页
vant 封装日期段选择器

vant 封装日期段选择器

作者: 请叫我彭彭 | 来源:发表于2022-01-10 10:32 被阅读0次

    组件代码

    <template>
      <van-popup v-model:show="props.visible" position="bottom" @close="closePopup">
        <van-picker v-bind="$attrs" :columns="columns" @change="onChange" @confirm="onConfirm" @cancel="closePopup" />
      </van-popup>
    </template>
    
    <script lang="ts" setup>
    import dayjs from 'dayjs'
    import { ref, computed } from 'vue'
    
    interface IProps {
      /** 窗口是否显示 */
      visible: boolean
      /** 时间段 */
      dates?: Date[]
      /** 分割符 */
      apart?: string
      /** 最大年限 */
      maxDate?: Date
      /** 最小年限 */
      minDate?: Date
      /** 显示的格式 */
      format?: string
      /** 是否显示日期 */
      showDate?: boolean
      /** 是否显示 小时 */
      showHour?: boolean
    }
    
    type dateType = {
      startYear: string
      startMonth: string
      startDate: string
      startHour: string
      startMinute: string
      endYear: string
      endMonth: string
      endDate: string
      endHour: string
      endMinute: string
    }
    
    /** 最终返回的结果 */
    const timeValue = ref<string[]>([])
    
    const props = withDefaults(defineProps<IProps>(), {
      apart: '~',
      minDate: () => new Date('2020/01/01 00:00'),
      maxDate: () => new Date('2099/12/31 23:59'),
      showDate: true,
      showHour: false,
      format: 'YYYY-MM-DD',
      dates: () => {
        return [new Date(), new Date()]
      }
    })
    
    const emit = defineEmits<{
      (e: 'update:visible', value: Boolean): void
      (e: 'confirm', value: string[]): void
    }>()
    
    /** 配置列 */
    interface column {
      values: string[] | number[] | string
      defaultIndex: number
    }
    
    /** 根据最小数值 、最大数值 得到一个数组 */
    function getArray(min: number, max: number) {
      const arr: string[] = []
      for (let i = min; i <= max; i++) {
        arr.push((i + '').padStart(2, '0'))
      }
      return arr
    }
    
    /** 根据开始日期,结束日期 需要格式 */
    function getResult(start: string | Date, end: string | Date): dateType {
      /** 开始日期*/
      const startDate = dayjs(start)
      /** 结束日期 */
      const endDate = dayjs(end)
    
      return {
        startYear: startDate.format('YYYY'),
        startMonth: startDate.format('MM'),
        startDate: startDate.format('DD'),
        startHour: startDate.format('HH'),
        startMinute: startDate.format('mm'),
    
        endYear: endDate.format('YYYY'),
        endMonth: endDate.format('MM'),
        endDate: endDate.format('DD'),
        endHour: endDate.format('HH'),
        endMinute: endDate.format('mm')
      } as dateType
    }
    
    /** 得到最终的格式 */
    const result = computed(() => {
      if (props.dates.length !== 2) throw new Error('时间格式错误')
      return getResult(props.dates[0], props.dates[1])
    })
    
    const list = computed(() => {
      return getResult(props.minDate, props.maxDate)
    })
    
    /** 年份 */
    const years = computed(() => {
      return getArray(Number(list.value.startDate), Number(list.value.endYear))
    })
    
    /** 月份 */
    const months = computed(() => {
      return getArray(Number(list.value.startMonth), Number(list.value.endMonth))
    })
    
    /** 天数 */
    const days = computed(() => {
      return getArray(Number(list.value.startDate), Number(list.value.endDate))
    })
    
    /** 小时 */
    const hours = computed(() => {
      return getArray(Number(list.value.startHour), Number(list.value.endHour))
    })
    
    /**  分钟 */
    const minutes = computed(() => {
      return getArray(Number(list.value.startMinute), Number(list.value.endMinute))
    })
    
    const columns = computed(() => {
      /** 开始年份 */
      const startYear: column = { values: years.value, defaultIndex: years.value.findIndex((e) => e === result.value.startYear) }
      /** 结束年份  */
      const endYear: column = { values: years.value, defaultIndex: years.value.findIndex((e) => e === result.value.endYear) }
    
      /** 开始月份 */
      const startMonth: column = { values: months.value, defaultIndex: Number(result.value.startMonth) - 1 }
      /** 结束月份 */
      const endMonth: column = { values: months.value, defaultIndex: Number(result.value.endMonth) - 1 }
    
      /** 开始天数 */
      const startDay: column = { values: days.value, defaultIndex: Number(result.value.startDate) - 1 }
      /** 结束天数 */
      const endDay: column = { values: days.value, defaultIndex: Number(result.value.endDate) - 1 }
    
      /** 开始 小时 */
      const startHour: column = { values: hours.value, defaultIndex: Number(result.value.startHour) }
      /** 开始 小时 */
      const endHour: column = { values: hours.value, defaultIndex: Number(result.value.endHour) }
    
      /** 开始 小时 */
      const startMinute: column = { values: minutes.value, defaultIndex: Number(result.value.startMinute) }
      /** 开始 小时 */
      const endMinute: column = { values: minutes.value, defaultIndex: Number(result.value.endMinute) }
    
      let columns: column[] = []
    
      if (props.showDate) {
        columns = [startYear, startMonth, startDay]
      }
      if (props.showHour) {
        columns = [...columns, startHour, startMinute]
      }
    
      columns.push({ values: [props.apart], defaultIndex: 0 })
    
      if (props.showDate) {
        columns = [...columns, endYear, endMonth, endDay]
      }
      if (props.showHour) {
        columns = [...columns, endHour, endMinute]
      }
      return columns
    })
    
    /** 选择时间段取消事件 */
    function closePopup() {
      emit('update:visible', false)
    }
    
    /** 日期格式化 */
    function dateFormat(date: string | Date) {
      return dayjs(date).format(props.format)
    }
    
    /** 选择时间段确认事件 */
    function onConfirm() {
      if (timeValue.value.length > 0) {
        emit('confirm', timeValue.value)
      } else {
        emit('confirm', [dateFormat(props.dates[0]), dateFormat(props.dates[1])])
      }
      closePopup()
    }
    
    /** 选择时间段值改变事件 */
    function onChange(values: string[]) {
      let start = ''
      let end = ''
    
      if (props.showDate && props.showHour) {
        const [startYear, startMonth, startDate, startHour, startMinute, apart, endYear, endMonth, endDate, endHour, endMinute] = values
        start = `${startYear}/${startMonth}/${startDate} ${startHour}:${startMinute}`
        end = `${endYear}/${endMonth}/${endDate} ${endHour}:${endMinute}`
      } else if (props.showDate && !props.showHour) {
        const [startYear, startMonth, startDate, apart, endYear, endMonth, endDate] = values
        start = `${startYear}/${startMonth}/${startDate}`
        end = `${endYear}/${endMonth}/${endDate}`
      } else if (props.showHour && !props.showDate) {
        const [startHour, startMinute, apart, endHour, endMinute] = values
        start = `2011/1/1 ${startHour}:${startMinute}`
        end = `2011/1/1 ${endHour}:${endMinute}`
      }
      timeValue.value = [dateFormat(start), dateFormat(end)]
    }
    </script>
    
    

    代码示例

    <template>
      <PickerDateTimeRangeVue v-model:visible="dateVisible" :dates="defaultDate" @confirm="(values:string[])=>showDate=values.join('~')" />
    <template>
    
    <script lang="ts" setup>
    import { ref, watch, onBeforeMount } from 'vue'
    /** 选择日期是否显示 */
    const dateVisible = ref(false)
    const defaultDate = ref<Date[]>([new Date(startDate), new Date(endDate)])
    
    /** 日期查询条件 */
    const startDate = dayjs().add(-7, 'days').format('YYYY-MM-DD')
    const endDate = dayjs().add(-1, 'days').format('YYYY-MM-DD')
    const showDate = ref(`${startDate}~${endDate}`)
    </script>
    

    ui效果

    image.png

    参数

    参数 说明 类型 可选值 默认值
    visible 窗口是否显示 boolean true/false false
    dates 日期段 Date[] - [new Date(), new Date()]
    apart 中间分割符 string - ~
    maxDate 最大日期 Date - new Date('2099/12/31 23:59')
    minDate 最小日期 Date - new Date('2020/01/01 00:00')
    format 日期格式化格式 string - YYYY-MM-DD
    showDate 是否显示日期 boolean - true
    showHour 是否显示小时 boolean - false

    事件

    事件名称 说明 回调参数
    update:visible 关闭窗口 是否关闭窗口(true /false)
    confirm 确认事件 返回一个数组

    相关文章

      网友评论

          本文标题:vant 封装日期段选择器

          本文链接:https://www.haomeiwen.com/subject/vlrmcrtx.html