Vue3+AntDesign实现既能输入又能选择的日期组件
<template>
<div class="input-date-picker">
<!-- 输入框 -->
<a-input
v-model:value="inputValue"
:placeholder="placeholder"
@blur="handleBlur"
@pressEnter="handleBlur"
>
<template #suffix>
<!-- 点击 icon 才打开 -->
<CalendarOutlined @click.stop="openPanel" style="cursor: pointer;" />
</template>
</a-input>
<!-- 隐藏的 DatePicker -->
<a-date-picker
v-model:value="innerValue"
:open="open"
@openChange="(val) => open = val"
@change="handleSelect"
style="position: absolute; opacity: 0; pointer-events: none;"
/>
</div>
</template>
<script setup>
import { ref, watch } from 'vue'
import dayjs from 'dayjs'
import { CalendarOutlined } from '@ant-design/icons-vue'
const props = defineProps({
modelValue: String,
placeholder: {
type: String,
default: '请输入日期(YYYY/MM/DD)'
},
format: {
type: String,
default: 'YYYY/MM/DD'
},
valueFormat: {
type: String,
default: 'YYYY-MM-DD'
}
})
const emit = defineEmits(['update:modelValue'])
const open = ref(false)
const inputValue = ref('')
const innerValue = ref(null)
// 打开面板(只允许 icon 触发)
const openPanel = () => {
open.value = true
}
// 输入框失焦 → 解析日期
const handleBlur = () => {
if (!inputValue.value) {
emit('update:modelValue', undefined)
innerValue.value = null
return
}
const parsed = dayjs(inputValue.value, props.format, true)
if (parsed.isValid()) {
innerValue.value = parsed
emit('update:modelValue', parsed.format(props.valueFormat))
} else {
// ❗非法输入处理(可扩展提示)
innerValue.value = null
emit('update:modelValue', undefined)
}
}
// 面板选择 → 回填 input
const handleSelect = (val) => {
if (!val) return
inputValue.value = val.format(props.format)
emit('update:modelValue', val.format(props.valueFormat))
open.value = false
}
// 外部值同步进来
watch(
() => props.modelValue,
(val) => {
if (!val) {
inputValue.value = ''
innerValue.value = null
} else {
const d = dayjs(val)
inputValue.value = d.format(props.format)
innerValue.value = d
}
},
{ immediate: true }
)
</script>
<style scoped>
.input-date-picker {
position: relative;
}
</style>
学而不思则罔,思而不学则殆!

浙公网安备 33010602011771号