本组件基于 @vuepic/vue-datepicker@9.0.1 进行二次封装,以便更适合日常使用!
官方文档:https://vue3datepicker.com/installation/
除了范围选择器、年选择器以外,其余选择的日期(v-model)均默认返回字符串指定格式日期!
可自定义设置以下二次封装属性(也可根据官方文档设定相应属性,组件已设置继承所有属性):
日期选择器宽度(width),类型:number,单位px,默认 180
选择器模式(mode),类型:'time' | 'date' | 'week' | 'month' | 'year',默认 'date'
日期展示格式(format),类型:string | ((date: Date) => string) | ((dates: Date[]) => string),默认 DefaultFormat
是否增加时间选择(showTime),类型:boolean,默认 false
是否展示”今天“按钮(showToday),类型:boolean,默认 false
双向绑定值(modelValue),类型:number | string | object | array,默认 null
v-model 值的类型(modelType),类型:'timestamp' | 'format',默认 'format',可选
timestamp
: 时间戳、format
: 字符串,mode
为week
或year
时,该配置不生效
更多使用方式还请查阅官方文档,功能设计非常全面,各部分主题颜色也均可自定义修改!
常用官方属性举例:
- 日期展示格式(format),类型:string | ((date: Date) => string) | ((dates: Date[]) => string),默认 DefaultFormat
format 支持的格式化占位符为:
yy: 年, M: 月, d: 天, H: 时, m: 分, s: 秒, w: 周
其中 DefaultFormat 取值如下:
范围选择器是否使用双日期面板(multiCalendars),类型:boolean,默认 false
定义选择顺序(flow),类型:array,默认 [],可选 ("calendar" | "time" | "month" | "year" | "minutes" | "hours" | "seconds")[]
样式主题是否使用黑色(dark),类型:boolean,默认 false
是否展示秒选择(enable-seconds),类型:boolean,默认 false
效果如下图:在线预览
①创建日期选择器组件DatePicker.vue:
<script setup lang="ts">
defineOptions({
inheritAttrs: false
})
import VueDatePicker from '@vuepic/vue-datepicker'
import '@vuepic/vue-datepicker/dist/main.css'
import { computed } from 'vue'
interface Props {
width?: number // 日期选择器宽度
mode?: 'time' | 'date' | 'week' | 'month' | 'year' // 选择器模式,可选:时间time,日期date,周week,月month,年year
// format?: string | ((date: Date) => string) | ((dates: Date[]) => string) // 日期展示格式,(yy: 年, M: 月, d: 天, H: 时, m: 分, s: 秒, w: 周)
showTime?: boolean // 是否增加时间选择
showToday?: boolean // 是否展示”今天“按钮
// multiCalendars?: boolean // 范围选择器是否使用双日期面板
// flow?: any[] // 定义选择顺序 ("calendar" | "time" | "month" | "year" | "minutes" | "hours" | "seconds")[]
// dark?: boolean // 样式主题是否使用黑色
modelType?: 'timestamp' | 'format' // v-model 值类型,可选 timestamp: 时间戳、format: 字符串,mode 为 week 或 year 时,该配置不生效
}
const props = withDefaults(defineProps<Props>(), {
width: 180,
mode: 'date',
/* format default
Single picker: 'MM/dd/yyyy HH:mm'
Range picker: 'MM/dd/yyyy HH:mm - MM/dd/yyyy HH:mm'
Month picker: 'MM/yyyy'
Time picker: 'HH:mm'
Time picker range: 'HH:mm - HH:mm'
Week picker: 'ww-yyyy'
*/
showTime: false,
showToday: false,
// multiCalendars: false,
// flow: () => [],
// dark: false,
modelType: 'format'
})
const time = computed(() => {
return props.mode === 'time'
})
const week = computed(() => {
return props.mode === 'week'
})
const month = computed(() => {
return props.mode === 'month'
})
const year = computed(() => {
return props.mode === 'year'
})
// const format = (date: Date) => {
// const day = date.getDate()
// const month = date.getMonth() + 1
// const year = date.getFullYear()
// return `${year}-${month}-${day}`
// }
</script>
<template>
<div class="m-datepicker" :style="`width: ${width}px;`">
<VueDatePicker
locale="zh-CN"
:month-change-on-scroll="false"
:enable-time-picker="showTime"
:time-picker="time"
:week-picker="week"
:month-picker="month"
:year-picker="year"
now-button-label="今天"
:show-now-button="showToday"
auto-apply
text-input
:model-type="modelType"
:day-names="['一', '二', '三', '四', '五', '六', '七']"
v-bind="$attrs"
></VueDatePicker>
</div>
</template>
<style lang="less" scoped>
.m-datepicker {
display: inline-block;
}
.dp__theme_dark {
// dark theme
--dp-background-color: #212121;
--dp-text-color: #ffffff;
--dp-hover-color: #484848;
--dp-hover-text-color: #ffffff;
--dp-hover-icon-color: #959595;
--dp-primary-color: #005cb2;
--dp-primary-text-color: #ffffff;
--dp-secondary-color: #a9a9a9;
--dp-border-color: #2d2d2d;
--dp-menu-border-color: #2d2d2d;
--dp-border-color-hover: #aaaeb7;
--dp-disabled-color: #737373;
--dp-scroll-bar-background: #212121;
--dp-scroll-bar-color: #484848;
--dp-success-color: #00701a;
--dp-success-color-disabled: #428f59;
--dp-icon-color: #959595;
--dp-danger-color: #e53935;
--dp-highlight-color: rgba(0, 92, 178, 0.2);
}
.dp__theme_light {
// light theme
--dp-background-color: #ffffff;
--dp-text-color: #212121;
--dp-hover-color: #f3f3f3;
--dp-hover-text-color: #212121;
--dp-hover-icon-color: #959595;
--dp-primary-color: #1976d2;
--dp-primary-text-color: #f8f5f5;
--dp-secondary-color: #c0c4cc;
--dp-border-color: #ddd;
--dp-menu-border-color: #ddd;
--dp-border-color-hover: #aaaeb7;
--dp-disabled-color: #f6f6f6;
--dp-scroll-bar-background: #f3f3f3;
--dp-scroll-bar-color: #959595;
--dp-success-color: #76d275;
--dp-success-color-disabled: #a3d9b1;
--dp-icon-color: #959595;
--dp-danger-color: #ff6f60;
--dp-highlight-color: rgba(25, 118, 210, 0.1);
}
</style>
②在要使用的页面引入:
<script setup lang="ts">
import DatePicker from './DatePicker.vue'
import pkg from '/package.json'
import { ref, watchEffect } from 'vue'
import {
format,
endOfMonth,
endOfYear,
startOfMonth,
startOfYear,
subMonths,
addDays,
startOfWeek,
endOfWeek,
addHours,
addMinutes,
addSeconds
} from 'date-fns'
const dateValue = ref(format(new Date(), 'yyyy-MM-dd'))
const dateTimeValue = ref(format(new Date(), 'yyyy-MM-dd HH:mm:ss'))
const rangeValue = ref<string[]>([format(new Date(), 'yyyy-MM-dd'), format(addDays(new Date(), 1), 'yyyy-MM-dd')])
console.log(addHours(Date.now(), 1))
console.log('rangeValue', rangeValue.value)
const timeRangeValue = ref([
{
hours: new Date().getHours(),
minutes: new Date().getMinutes(),
seconds: new Date().getSeconds()
},
{
hours: addHours(Date.now(), 1).getHours(),
minutes: addMinutes(Date.now(), 10).getMinutes(),
seconds: addSeconds(Date.now(), 30).getSeconds()
}
])
const presetDates = ref([
{ label: 'Today', value: [new Date(), new Date()] },
{ label: 'This month', value: [startOfMonth(new Date()), endOfMonth(new Date())] },
{
label: 'Last month',
value: [startOfMonth(subMonths(new Date(), 1)), endOfMonth(subMonths(new Date(), 1))]
},
{ label: 'This year', value: [startOfYear(new Date()).getTime(), endOfYear(new Date()).getTime()] }
])
const timeValue = ref({
hours: new Date().getHours(),
minutes: new Date().getMinutes()
})
const secondsValue = ref({
hours: new Date().getHours(),
minutes: new Date().getMinutes(),
seconds: new Date().getSeconds()
})
// startOfWeek & endOfWeek 默认以周日作为一周的开始,可以传递一个选项对象,以周一作为一周的开始:{ weekStartsOn: 1 }
const options: any = { weekStartsOn: 1 }
const weekValue = ref([startOfWeek(new Date(), options), endOfWeek(new Date(), options)])
const monthValue = ref({
year: new Date().getFullYear(),
month: new Date().getMonth()
})
const yearValue = ref(new Date().getFullYear())
watchEffect(() => {
console.log('dateValue:', dateValue.value)
})
watchEffect(() => {
console.log('dateTimeValue:', dateTimeValue.value)
})
watchEffect(() => {
console.log('rangeValue:', rangeValue.value)
})
watchEffect(() => {
console.log('timeRangeValue:', timeRangeValue.value)
})
watchEffect(() => {
console.log('timeValue:', timeValue.value)
})
watchEffect(() => {
console.log('secondsValue:', secondsValue.value)
})
watchEffect(() => {
console.log('weekValue:', weekValue.value)
})
watchEffect(() => {
console.log('monthValue:', monthValue.value)
})
watchEffect(() => {
console.log('yearValue:', yearValue.value)
})
</script>
<template>
<div>
<h1>{
{ $route.name }} {
{ $route.meta.title }}</h1>
<ul class="m-list">
<li>
<a class="u-file" href="https://vue3datepicker.com/" target="_blank">Vue Datepicker</a>
</li>
<li>
<a class="u-file" href="https://vue3datepicker.com/installation/" target="_blank">Vue Datepicker Documents</a>
</li>
</ul>
<Space class="mt30" gap="small">
<h1>DatePicker</h1>
<Tag color="volcano">{
{ pkg.dependencies['@vuepic/vue-datepicker'] }}</Tag>
</Space>
<h2 class="mt30 mb10">基本使用</h2>
<DatePicker placeholder="请选择日期" v-model="dateValue" show-today format="yyyy-MM-dd" />
<h2 class="mt30 mb10">禁用过去</h2>
<DatePicker placeholder="请选择日期" v-model="dateValue" :min-date="new Date()" format="yyyy-MM-dd" />
<h2 class="mt30 mb10">禁用未来</h2>
<DatePicker placeholder="请选择日期" v-model="dateValue" :max-date="new Date()" format="yyyy-MM-dd" />
<h2 class="mt30 mb10">日期时间选择器</h2>
<DatePicker
placeholder="请选择日期时间"
v-model="dateTimeValue"
format="yyyy-MM-dd HH:mm:ss"
:width="240"
show-time
enable-seconds
/>
<h2 class="mt30 mb10">日期范围选择器</h2>
<DatePicker
placeholder="请选择日期范围"
v-model="rangeValue"
range
:preset-dates="presetDates"
format="yyyy-MM-dd"
:width="280"
/>
<h2 class="mt30 mb10">日期范围选择器,双日期面板</h2>
<DatePicker
placeholder="请选择日期范围"
v-model="rangeValue"
mode="range"
format="yyyy-MM-dd"
:width="280"
range
multi-calendars
/>
<h2 class="mt30 mb10">预设范围</h2>
<h3 class="mb10">预设常用的日期范围以提高用户体验</h3>
<DatePicker
placeholder="请选择日期范围"
mode="range"
format="yyyy-MM-dd"
:width="280"
range
:preset-dates="presetDates"
multi-calendars
v-model="rangeValue"
/>
<h2 class="mt30 mb10">时分选择器</h2>
<DatePicker
placeholder="请选择时间"
v-model="timeValue"
mode="time"
show-time
mode-height="120"
format="HH:mm"
:width="120"
/>
<h2 class="mt30 mb10">时分秒选择器</h2>
<DatePicker
placeholder="请选择时间"
v-model="secondsValue"
mode="time"
show-time
enable-seconds
mode-height="120"
format="HH:mm:ss"
:width="150"
/>
<h2 class="mt30 mb10">时分秒范围选择器</h2>
<DatePicker
placeholder="请选择时间"
v-model="timeRangeValue"
mode="time"
show-time
range
enable-seconds
mode-height="120"
format="HH:mm:ss"
:width="240"
/>
<h2 class="mt30 mb10"
>周选择器 ({
{ format(weekValue[0], 'yyyy-MM-dd') + ' - ' + format(weekValue[1], 'yyyy-MM-dd') }})</h2
>
<DatePicker placeholder="请选择周" v-model="weekValue" mode="week" format="yyyy年 第ww周" :width="200" />
<h2 class="mt30 mb10">月选择器</h2>
<DatePicker placeholder="请选择月" v-model="monthValue" mode="month" format="yyyy-MM" :width="150" />
<h2 class="mt30 mb10">年选择器</h2>
<DatePicker placeholder="请选择年" v-model="yearValue" mode="year" format="yyyy" :width="120" />
</div>
</template>