组件代码
<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 props {
/** 窗口是否显示 */
visible: boolean
/** 时间段 */
times?: string[]
/** 分割符 */
apart?: string
/** 最大时间 */
maxTime?: number
/** 最小时间 */
minTime?: number
/** 最大分钟数 */
maxMinute?: number
/** 最小分钟数 */
minMinute?: number
}
interface timeType {
/** 开始时间 */
startTime: string
/** 开始分钟 */
startMinute: string
/** 结束时间 */
endTime: string
/** 结束分钟 */
endMinute: string
}
/** 最终返回的结果 */
const timeValue = ref<string>('')
const props = withDefaults(defineProps<props>(), {
apart: '~',
maxTime: 12,
minTime: 1,
maxMinute: 59,
minMinute: 1,
times: () => {
return [dayjs().format('HH-mm'), dayjs().format('HH-mm')]
}
})
const emit = defineEmits<{
(e: 'update:visible', value: Boolean): void
(e: 'confirm', value: string): void
}>()
/** 配置列 */
interface column {
values: string[] | number[] | string
defaultIndex: number
}
/** 时段 */
const months: string[] = []
for (let i = props.minTime; i <= props.maxTime; i++) {
months.push((i + '').padStart(2, '0'))
}
/** 分钟 */
const days: string[] = []
for (let i = props.minMinute; i <= props.maxMinute; i++) {
days.push((i + '').padStart(2, '0'))
}
/** 得到最终的格式 */
const timeResult = computed(() => {
if (props.times.length !== 2) throw new Error('时间格式错误')
/** 开始时间 分秒*/
const startTimes = props.times[0].split('-')
/** 结束时间 分秒 */
const endTimes = props.times[1].split('-')
if (startTimes.length !== 2) throw new Error('开始时间格式错误')
else if (endTimes.length != 2) throw new Error('结束时间错误')
return {
startTime: startTimes[0],
startMinute: startTimes[1],
endTime: endTimes[0],
endMinute: endTimes[1]
} as timeType
})
const columns = ref<column[]>([
{
values: months, // 开始时
defaultIndex: Number(timeResult.value.startTime) - 1
},
{
values: days, // 开始分
defaultIndex: Number(timeResult.value.startMinute) - 1
},
{
values: [props.apart], // 分割符
defaultIndex: 0
},
{
values: months, // 结束时
defaultIndex: Number(timeResult.value.endTime) - 1
},
{
values: days, // 结束分
defaultIndex: Number(timeResult.value.endMinute) - 1
}
])
/** 选择时间段取消事件 */
function closePopup() {
emit('update:visible', false)
}
/** 选择时间段确认事件 */
function onConfirm() {
if (timeValue.value) {
emit('confirm', timeValue.value)
} else {
emit('confirm', `${props.times[0]}${props.apart}${props.times[1]}`)
}
closePopup()
}
/** 选择时间段值改变事件 */
function onChange(values: string[]) {
const reg = new RegExp(`-${props.apart}-`)
const result = values.join('-').replace(reg, props.apart)
timeValue.value = result
}
</script>
<style scoped lang="scss"></style>
代码示例
<template>
<PickerTime v-model:visible="chooseDateVisible" title="请选择预约时间" @confirm="onTimeConfirm" />
<template>
<script lang="ts" setup>
import { ref} from 'vue'
import PickerTime from './components/PickerTime '
const chooseDateVisible = ref(false)
/** 选择时间段确认事件 */
function onTimeConfirm(value: string) {
console.log(value)
}
</script>
ui效果
image.png具体文档参考vant-picktime,继承了vant-picker的所有属性
网友评论