介绍
组合了日历、弹出框组件,实现了便捷快速的日历选择功能。
代码演示
基础使用
使用 v-model 双向绑定当前值,使用 v-model:visible 控制弹出框显隐。
vue
<template>
<s-calendar-popout
v-model="value"
v-model:visible="visible"
title="请选择日期"
@change="onChange"
/>
<s-list card>
<s-list-item>
<s-button @click="visible = true">
{{ value ? formatDate(value, 'YYYY-MM-DD') : '请选择' }}
</s-button>
</s-list-item>
<s-list-item title="当前值:" :value="JSON.stringify(value) ?? 'undefined'" />
<s-list-item title="设置为今天" arrow hover @click="value = new Date()" />
<s-list-item title="清空" arrow hover @click="value = undefined" />
</s-list>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { formatDate } from 'sard'
const value = ref<Date | undefined>(new Date())
const visible = ref(false)
const onChange = (value: any) => {
console.log('change', value)
}
</script>vue
<template>
<s-calendar-popout
v-model="value"
v-model:visible="visible"
title="请选择日期"
@change="onChange"
/>
<s-list card>
<s-list-item>
<s-button @click="visible = true">
{{ value ? formatDate(value, 'YYYY-MM-DD') : '请选择' }}
</s-button>
</s-list-item>
<s-list-item title="当前值:" :value="JSON.stringify(value) ?? 'undefined'" />
<s-list-item title="设置为今天" arrow hover @click="value = new Date()" />
<s-list-item title="清空" arrow hover @click="value = undefined" />
</s-list>
</template>
<script setup lang="js">
import { ref } from 'vue'
import { formatDate } from 'sard'
const value = ref(new Date())
const visible = ref(false)
const onChange = (value) => {
console.log('change', value)
}
</script>类型
日历组件可以选择单个值、多个值以及进行范围选择。
vue
<template>
<s-calendar-popout
v-model="singleValue"
v-model:visible="singleVisible"
title="单个日期"
value-format="YYYY-MM-DD"
/>
<s-calendar-popout
v-model="mulitpleValue"
v-model:visible="mulitpleVisible"
type="multiple"
title="多个日期"
value-format="YYYY-MM-DD"
/>
<s-calendar-popout
v-model="rangeValue"
v-model:visible="rangeVisible"
type="range"
title="范围选择"
value-format="YYYY-MM-DD"
allow-same-day
/>
<s-list card>
<s-list-item
title="单个日期"
arrow
hover
:value="JSON.stringify(singleValue)"
@click="singleVisible = true"
/>
<s-list-item
title="多个日期"
arrow
hover
:value="JSON.stringify(mulitpleValue)"
@click="mulitpleVisible = true"
/>
<s-list-item
title="范围选择"
arrow
hover
:value="JSON.stringify(rangeValue)"
@click="rangeVisible = true"
/>
</s-list>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const singleValue = ref<string>()
const mulitpleValue = ref<string[]>()
const rangeValue = ref<string[]>()
const singleVisible = ref(false)
const mulitpleVisible = ref(false)
const rangeVisible = ref(false)
</script>vue
<template>
<s-calendar-popout
v-model="singleValue"
v-model:visible="singleVisible"
title="单个日期"
value-format="YYYY-MM-DD"
/>
<s-calendar-popout
v-model="mulitpleValue"
v-model:visible="mulitpleVisible"
type="multiple"
title="多个日期"
value-format="YYYY-MM-DD"
/>
<s-calendar-popout
v-model="rangeValue"
v-model:visible="rangeVisible"
type="range"
title="范围选择"
value-format="YYYY-MM-DD"
allow-same-day
/>
<s-list card>
<s-list-item
title="单个日期"
arrow
hover
:value="JSON.stringify(singleValue)"
@click="singleVisible = true"
/>
<s-list-item
title="多个日期"
arrow
hover
:value="JSON.stringify(mulitpleValue)"
@click="mulitpleVisible = true"
/>
<s-list-item
title="范围选择"
arrow
hover
:value="JSON.stringify(rangeValue)"
@click="rangeVisible = true"
/>
</s-list>
</template>
<script setup lang="js">
import { ref } from 'vue'
const singleValue = ref()
const mulitpleValue = ref()
const rangeValue = ref()
const singleVisible = ref(false)
const mulitpleVisible = ref(false)
const rangeVisible = ref(false)
</script>自定义日期范围
可以使用 min 和 max 属性限制可以选择的日期的范围。
vue
<template>
<s-calendar-popout
v-model="value"
v-model:visible="visible"
title="请选择日期"
:min="new Date(2000, 0, 7)"
:max="new Date(2000, 0, 21)"
value-format="YYYY-MM-DD"
/>
<s-list card>
<s-list-item
title="请选择日期"
arrow
hover
:value="JSON.stringify(value)"
@click="visible = true"
/>
</s-list>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const value = ref<string>()
const visible = ref(false)
</script>vue
<template>
<s-calendar-popout
v-model="value"
v-model:visible="visible"
title="请选择日期"
:min="new Date(2000, 0, 7)"
:max="new Date(2000, 0, 21)"
value-format="YYYY-MM-DD"
/>
<s-list card>
<s-list-item
title="请选择日期"
arrow
hover
:value="JSON.stringify(value)"
@click="visible = true"
/>
</s-list>
</template>
<script setup lang="js">
import { ref } from 'vue'
const value = ref()
const visible = ref(false)
</script>最多选择天数
在多个值和范围选择中,使用 maxDays 属性可以限制最多可选的天数。 超出允许选择的天数后会调用 overMaxDays 属性配置的函数。
vue
<template>
<s-calendar-popout
v-model="mulitpleValue"
v-model:visible="mulitpleVisible"
title="多个日期"
type="multiple"
:max-days="3"
:over-max-days="() => toast('最多选择3天')"
value-format="YYYY-MM-DD"
/>
<s-calendar-popout
v-model="rangeValue"
v-model:visible="rangeVisible"
title="范围选择"
type="range"
:max-days="3"
:over-max-days="() => toast('最多选择3天')"
value-format="YYYY-MM-DD"
/>
<s-list card>
<s-list-item
title="多个日期"
arrow
hover
:value="JSON.stringify(mulitpleValue)"
@click="mulitpleVisible = true"
/>
<s-list-item
title="范围选择"
arrow
hover
:value="JSON.stringify(rangeValue)"
@click="rangeVisible = true"
/>
</s-list>
</template>
<script setup lang="ts">
import { toast } from 'sard'
import { ref } from 'vue'
const mulitpleValue = ref<Date[]>()
const rangeValue = ref<Date[]>()
const mulitpleVisible = ref(false)
const rangeVisible = ref(false)
</script>vue
<template>
<s-calendar-popout
v-model="mulitpleValue"
v-model:visible="mulitpleVisible"
title="多个日期"
type="multiple"
:max-days="3"
:over-max-days="() => toast('最多选择3天')"
value-format="YYYY-MM-DD"
/>
<s-calendar-popout
v-model="rangeValue"
v-model:visible="rangeVisible"
title="范围选择"
type="range"
:max-days="3"
:over-max-days="() => toast('最多选择3天')"
value-format="YYYY-MM-DD"
/>
<s-list card>
<s-list-item
title="多个日期"
arrow
hover
:value="JSON.stringify(mulitpleValue)"
@click="mulitpleVisible = true"
/>
<s-list-item
title="范围选择"
arrow
hover
:value="JSON.stringify(rangeValue)"
@click="rangeVisible = true"
/>
</s-list>
</template>
<script setup lang="js">
import { toast } from 'sard'
import { ref } from 'vue'
const mulitpleValue = ref()
const rangeValue = ref()
const mulitpleVisible = ref(false)
const rangeVisible = ref(false)
</script>禁用日期
disabledDate 属性配置的函数接收一个日期对象,如果此函数返回真则禁用这个日期。
vue
<template>
<s-calendar-popout
v-model="value"
v-model:visible="visible"
title="请选择日期"
:disabled-date="disabledDate"
value-format="YYYY-MM-DD"
/>
<s-list card>
<s-list-item
title="请选择日期"
arrow
hover
:value="JSON.stringify(value)"
@click="visible = true"
/>
</s-list>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const value = ref<Date>()
const visible = ref(false)
const disabledDate = (date: Date) => {
return /0|6/.test(String(date.getDay()))
}
</script>vue
<template>
<s-calendar-popout
v-model="value"
v-model:visible="visible"
title="请选择日期"
:disabled-date="disabledDate"
value-format="YYYY-MM-DD"
/>
<s-list card>
<s-list-item
title="请选择日期"
arrow
hover
:value="JSON.stringify(value)"
@click="visible = true"
/>
</s-list>
</template>
<script setup lang="js">
import { ref } from 'vue'
const value = ref()
const visible = ref(false)
const disabledDate = (date) => {
return /0|6/.test(String(date.getDay()))
}
</script>自定义起始周
默认一周从星期天开始,使用 weekStartsOn 属性可以配置一周从任意星期开始。 0 表示从周日开始,1 表示从周一开始。
vue
<template>
<s-calendar-popout
v-model="value"
v-model:visible="visible"
title="请选择日期"
:week-starts-on="1"
value-format="YYYY-MM-DD"
/>
<s-list card>
<s-list-item
title="请选择日期"
arrow
hover
:value="JSON.stringify(value)"
@click="visible = true"
/>
</s-list>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const value = ref<Date>()
const visible = ref(false)
</script>vue
<template>
<s-calendar-popout
v-model="value"
v-model:visible="visible"
title="请选择日期"
:week-starts-on="1"
value-format="YYYY-MM-DD"
/>
<s-list card>
<s-list-item
title="请选择日期"
arrow
hover
:value="JSON.stringify(value)"
@click="visible = true"
/>
</s-list>
</template>
<script setup lang="js">
import { ref } from 'vue'
const value = ref()
const visible = ref(false)
</script>格式化日期
formatter 属性可以配置一个接收 CalendarDay 类型的对象,通过此对象可以自定义当前日期展示的内容和样式。
vue
<template>
<s-calendar-popout
v-model="value"
v-model:visible="visible"
title="请选择日期"
type="range"
:formatter="formatter"
:current-date="new Date(new Date().getFullYear(), 4, 1)"
value-format="YYYY-MM-DD"
/>
<s-list card>
<s-list-item
title="请选择日期"
arrow
hover
:value="JSON.stringify(value)"
@click="visible = true"
/>
</s-list>
</template>
<script setup lang="ts">
import type { CalendarDay } from 'sard'
import { ref } from 'vue'
const value = ref<Date>()
const visible = ref(false)
const formatter = (day: CalendarDay) => {
const year = day.date.getFullYear()
const month = day.date.getMonth() + 1
const date = day.date.getDate()
const week = day.date.getDay()
if (month === 5) {
if (date === 1) {
day.bottom = '劳动节'
}
if (date <= 3) {
day.top = '休'
}
if (date === 4) {
day.bottom = '青年节'
}
if (week === 0) {
const weekOnMonthStart = new Date(year, month - 1, 1).getDay()
const secondSunday = 15 - (weekOnMonthStart || 7)
if (secondSunday === date) {
day.bottom = '母亲节'
}
}
}
if (day.type === 'start') {
day.bottom = '入店'
} else if (day.type === 'end') {
day.bottom = '离店'
}
if (week === 0 || week === 6) {
day.style = {
fontWeight: 'bold',
color: 'var(--s-color-danger)',
}
}
}
</script>vue
<template>
<s-calendar-popout
v-model="value"
v-model:visible="visible"
title="请选择日期"
type="range"
:formatter="formatter"
:current-date="new Date(new Date().getFullYear(), 4, 1)"
value-format="YYYY-MM-DD"
/>
<s-list card>
<s-list-item
title="请选择日期"
arrow
hover
:value="JSON.stringify(value)"
@click="visible = true"
/>
</s-list>
</template>
<script setup lang="js">
import { ref } from 'vue'
const value = ref()
const visible = ref(false)
const formatter = (day) => {
const year = day.date.getFullYear()
const month = day.date.getMonth() + 1
const date = day.date.getDate()
const week = day.date.getDay()
if (month === 5) {
if (date === 1) {
day.bottom = '劳动节'
}
if (date <= 3) {
day.top = '休'
}
if (date === 4) {
day.bottom = '青年节'
}
if (week === 0) {
const weekOnMonthStart = new Date(year, month - 1, 1).getDay()
const secondSunday = 15 - (weekOnMonthStart || 7)
if (secondSunday === date) {
day.bottom = '母亲节'
}
}
}
if (day.type === 'start') {
day.bottom = '入店'
} else if (day.type === 'end') {
day.bottom = '离店'
}
if (week === 0 || week === 6) {
day.style = {
fontWeight: 'bold',
color: 'var(--s-color-danger)',
}
}
}
</script>展示多个月
默认只展示一个月,如果要表现上下月之间的强关联性,可以设置 severalMonths 属性以展示多个月。 这时设置的最大最小值范围不能太大,避免渲染大量节点造成性能问题。
vue
<template>
<s-calendar-popout
v-model="value"
v-model:visible="visible"
title="请选择日期"
type="range"
several-months
value-format="YYYY-MM-DD"
/>
<s-list card>
<s-list-item
title="请选择日期"
arrow
hover
:value="JSON.stringify(value)"
@click="visible = true"
/>
</s-list>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const value = ref<Date[]>()
const visible = ref(false)
</script>vue
<template>
<s-calendar-popout
v-model="value"
v-model:visible="visible"
title="请选择日期"
type="range"
several-months
value-format="YYYY-MM-DD"
/>
<s-list card>
<s-list-item
title="请选择日期"
arrow
hover
:value="JSON.stringify(value)"
@click="visible = true"
/>
</s-list>
</template>
<script setup lang="js">
import { ref } from 'vue'
const value = ref()
const visible = ref(false)
</script>API
CalendarPopoutProps
继承 CalendarProps 和 FormPopoutProps。
CalendarPopoutSlots
| 插槽 | 描述 | 属性 |
|---|---|---|
| title | 自定义标题 | - |
| title-prepend | 自定义标题前面内容 | - |
CalendarPopoutEmits
继承 MotionEmits。
| 事件 | 描述 | 类型 |
|---|---|---|
| update:visible | 弹出框显隐时触发 | (visible: boolean) => void |
| update:modelValue | 日历组件值改变时触发 | (value: Date | Date[] | string | string[] | undefined) => void |
| change | 日历组件值改变时触发 | (value: Date | Date[] | string | string[] | undefined) => void |
| confirm | 点击确定按钮时触发 | (value: Date | Date[] | string | string[] | undefined) => void |