Vue3组合式API日期时间输入限制及已选时间禁用问题
Vue3 预约表单:时间输入限制与已选时间禁用方案
针对你的两个需求,以下是具体实现方案:
一、动态设置时间输入的 max/min 限制
原生 input[type="time"] 支持通过 :min 和 :max 属性限制可选时间范围,结合选中的日期动态调整规则:
- 若选择当日,时间最小值设为当前时间(防止选择过去的时段),最大值设为营业结束时间
- 若选择未来日期,时间范围直接限制在营业时间内
<script setup> import { ref, watch } from 'vue' const selectedDate = ref(new Date().toISOString().split('T')[0]) const selectedTime = ref('') // 自定义营业时间 const businessStart = '09:00' const businessEnd = '18:00' const timeMin = ref(businessStart) const timeMax = ref(businessEnd) // 监听日期变化,动态更新时间限制 watch(selectedDate, (newDate) => { const today = new Date().toISOString().split('T')[0] if (newDate === today) { // 格式化当前时间为 HH:mm const now = new Date() const currentHour = String(now.getHours()).padStart(2, '0') const currentMinute = String(now.getMinutes()).padStart(2, '0') timeMin.value = `${currentHour}:${currentMinute}` } else { timeMin.value = businessStart } timeMax.value = businessEnd }) </script> <template> <input type="date" v-model="selectedDate" :min="new Date().toISOString().split('T')[0]" > <input type="time" v-model="selectedTime" :min="timeMin" :max="timeMax" > </template>
二、禁用已被选择的时间
原生时间输入框无法直接禁用特定时段,建议通过生成可选时间列表的方式实现,过滤掉已预约的时段:
- 维护一个已预约时间的数组(可从后端接口获取)
- 根据选中日期和营业时间,生成所有可选时段,标记已预约的时段为禁用状态
- 使用下拉选择框或自定义选择器展示可选时间
<script setup> import { ref, computed } from 'vue' const selectedDate = ref(new Date().toISOString().split('T')[0]) const selectedTime = ref('') const businessStart = '09:00' const businessEnd = '18:00' // 模拟已预约的时间数据 const bookedTimes = ref([ { date: '2024-05-20', time: '10:00' }, { date: '2024-05-20', time: '14:30' } ]) // 计算生成可选时间列表(按30分钟间隔) const availableTimes = computed(() => { const times = [] const startMs = new Date(`2000-01-01 ${businessStart}`).getTime() const endMs = new Date(`2000-01-01 ${businessEnd}`).getTime() const interval = 30 * 60 * 1000 // 30分钟间隔 // 当日从当前时间之后开始(向上取整到最近的间隔) const today = new Date().toISOString().split('T')[0] let currentMs = startMs if (selectedDate.value === today) { const nowMs = new Date().getTime() const todayStartMs = new Date(`${today} ${businessStart}`).getTime() // 若当前时间早于营业开始,从营业开始时间算 currentMs = nowMs < todayStartMs ? todayStartMs : nowMs // 向上取整到间隔时间 const remainder = currentMs % interval currentMs = remainder ? currentMs + (interval - remainder) : currentMs } // 生成所有可选时段 while (currentMs <= endMs) { const timeStr = new Date(currentMs).toTimeString().slice(0, 5) // 检查该时段是否已被预约 const isBooked = bookedTimes.value.some(item => item.date === selectedDate.value && item.time === timeStr ) times.push({ time: timeStr, disabled: isBooked || currentMs < startMs }) currentMs += interval } return times }) // 提交预约,添加到已预约列表 const submitBooking = () => { if (selectedTime.value) { bookedTimes.value.push({ date: selectedDate.value, time: selectedTime.value }) selectedTime.value = '' } } </script> <template> <input type="date" v-model="selectedDate" :min="new Date().toISOString().split('T')[0]" > <select v-model="selectedTime"> <option value="">请选择时段</option> <option v-for="item in availableTimes" :key="item.time" :value="item.time" :disabled="item.disabled" > {{ item.time }} {{ item.disabled ? '(已预约)' : '' }} </option> </select> <button @click="submitBooking" :disabled="!selectedTime">提交预约</button> </template>
内容的提问来源于stack exchange,提问作者coochie
相关产品推荐
相关产品推荐

