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>
posted @ 2026-03-31 12:58  Felix_Openmind  阅读(35)  评论(0)    收藏  举报
*{cursor: url(https://files-cdn.cnblogs.com/files/morango/fish-cursor.ico),auto;}