| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- <template>
- <div class="date-picker-container">
- <!-- 使用van-field作为输入框,优化移动端点击体验 -->
- <van-field
- v-model="displayDate"
- :label="label"
- readonly
- :required="required"
- clickable
- :placeholder="placeholder"
- @click="showPicker = true"
- :error-message="error"
- >
- <template #right-icon>
- <van-icon name="calendar-o" class="calendar-icon" />
- </template>
- </van-field>
- <!-- 日期选择弹窗 -->
- <van-popup
- v-model="showPicker"
- position="bottom"
- round
- >
- <van-datetime-picker
- v-model="currentDate"
- type="date"
- :min-date="minDate"
- :max-date="maxDate"
- :formatter="formatter"
- @confirm="onConfirm"
- @cancel="showPicker = false"
- />
- </van-popup>
- </div>
- </template>
- <script>
- export default {
- props: {
- value: {
- type: [String, Date],
- default: ''
- },
- label: String,
- required: {
- type: Boolean,
- default: false
- },
- placeholder: {
- type: String,
- default: '请选择日期'
- },
- // 新增日期格式配置
- dateFormat: {
- type: String,
- default: 'yyyy-MM-dd'
- },
- error: {
- type: String,
- default: ''
- }
- },
- data() {
- return {
- showPicker: false,
- currentDate: this.value ? new Date(this.value) : new Date(),
- minDate: new Date(1990, 0, 1),
- maxDate: new Date()
- }
- },
- computed: {
- // 显示格式化后的日期
- displayDate: {
- get() {
- return this.formatDate(this.currentDate)
- },
- set() {} // 避免直接修改警告
- }
- },
- watch: {
- value: {
- handler(newVal) {
- if (newVal) {
- this.currentDate = this.parseDate(newVal)
- }
- },
- immediate: true
- }
- },
- methods: {
- // 日期确认处理
- onConfirm(value) {
- this.currentDate = value
- this.$emit('input', this.formatDate(value))
- this.showPicker = false
- },
- // 日期格式化方法
- formatDate(date) {
- if (!(date instanceof Date)) return ''
- const pad = n => n.toString().padStart(2, '0')
- return this.dateFormat
- .replace('yyyy', date.getFullYear())
- .replace('MM', pad(date.getMonth() + 1))
- .replace('dd', pad(date.getDate()))
- },
- // 字符串转Date对象
- parseDate(dateStr) {
- if (dateStr instanceof Date) return dateStr
- return new Date(dateStr.replace(/-/g, '/'))
- },
- // 自定义日期显示格式
- formatter(type, value) {
- if (type === 'year') return `${value}年`
- if (type === 'month') return `${value}月`
- if (type === 'day') return `${value}日`
- return value
- }
- }
- }
- </script>
- <style scoped>
- .date-picker-container {
- display: flex;
- align-items: center;
- gap: 12px;
- width: 100%;
- padding: 12px 0;
- box-sizing: border-box;
- }
- /* 移动端适配 */
- @media (max-width: 768px) {
- .date-picker-container {
- flex-direction: column;
- align-items: flex-start;
- }
- .custom-label {
- width: 100% !important;
- margin-bottom: 8px;
- }
- }
- /* Vant组件样式覆盖 */
- .calendar-icon {
- color: #1989fa;
- font-size: 18px;
- }
- /* 必填星号样式 */
- .required-star {
- color: #ff4444;
- margin-left: 4px;
- }
- /* 标签样式优化 */
- .custom-label {
- flex: 0 0 auto;
- font-size: 14px;
- color: #333;
- min-width: 6em;
- }
- </style>
|