Skip to content

Calendar 日历选择器

14:29

组件概况

组件概述

Calendar 日历选择器组件是一个功能强大的日期时间选择器,支持多种选择模式,包括单个日期、日期范围、时间日期、周、月等,可用于表单输入、日期筛选等多种场景。

详细功能描述

  • 支持9种选择类型:date(日期)、dates(多日期)、datetime(日期时间)、week(周)、month(月)、daterange(日期范围)、datetimerange(日期时间范围)、weekrange(周范围)、monthrange(月范围)
  • 支持最小/最大日期限制
  • 支持周起始天设置
  • 支持自定义日期格式化
  • 支持范围选择的最大范围限制
  • 支持快捷选项
  • 支持时间过滤
  • 支持隐藏秒选择
  • 支持底部安全距离适配
  • 支持懒渲染
  • 支持从页面中脱离(解决fixed失效问题)
  • 支持表单验证
  • 支持清空功能
  • 支持必填标记

适用业务场景

  • 表单中的日期选择
  • 订单日期选择
  • 日期范围筛选(如报表查询)
  • 周/月选择
  • 任何需要日期时间选择的场景

完整API参考

Props属性

名称类型默认值必填描述
modelValuenumber/array/null-选中值,为13位时间戳或时间戳数组
typestringdate日期类型,可选值:date / dates / datetime / week / month / daterange / datetimerange / weekrange / monthrange
minDatenumber当前日期前12个月最小日期,为13位时间戳
maxDatenumber当前日期后12个月最大日期,为13位时间戳
firstDayOfWeeknumber0周起始天(0-周日,1-周一,以此类推)
formatterfunction-日期格式化函数
maxRangenumber-type为范围选择时有效,最大日期范围
rangePromptstring-type为范围选择时有效,选择超出最大日期范围时的错误提示文案
allowSameDaybooleanfalsetype为范围选择时有效,是否允许选择同一天
defaultTimestring/array-选中日期所使用的当日内具体时刻
timeFilterfunction-type为datetime或datetimerange时有效,用于过滤时间选择器的数据
hideSecondbooleanfalsetype为datetime或datetimerange时有效,是否不展示秒修改
labelstring-选择器左侧文案
labelWidthstring33%设置左侧标题宽度
disabledbooleanfalse是否禁用
readonlybooleanfalse是否只读
placeholderstring-选择器占位符
titlestring-弹出层标题
alignRightbooleanfalse选择器的值靠右展示
errorbooleanfalse是否为错误状态,错误状态时右侧内容为红色
requiredbooleanfalse是否必填
sizestring-设置选择器大小,可选值:large
centerbooleanfalse是否垂直居中
closeOnClickModalbooleantrue点击遮罩是否关闭
zIndexnumber15弹框层级
showConfirmbooleantrue是否显示确定按钮
confirmTextstring-确定按钮文字
displayFormatfunction-自定义展示文案的格式化函数,返回一个字符串
innerDisplayFormatfunction-自定义范围选择类型的面板内部回显,返回一个字符串
ellipsisbooleanfalse是否超出隐藏
showTypeSwitchbooleanfalse是否显示类型切换功能
shortcutsarray[]快捷选项,为对象数组,其中对象的text必传
onShortcutsClickfunction-快捷操作点击回调
safeAreaInsetBottombooleantrue弹出面板是否设置底部安全距离(iphone X类型的机型)
beforeConfirmfunction-确定前校验函数,接收{ value, resolve }参数,通过resolve继续执行
propstring-表单域model字段名,在使用表单校验功能的情况下,该属性是必填的
rulesarray[]表单验证规则,结合wd-form组件使用
immediateChangebooleanfalse是否在手指松开时立即触发change事件(仅微信/支付宝小程序支持)
withCellbooleantrue是否使用内置单元格
rootPortalbooleanfalse是否从页面中脱离出来,解决fixed失效问题
markerSidestringbefore必填标记位置,可选值:before(标签前)、after(标签后)
clearablebooleanfalse是否显示清空按钮
customStylestring-自定义根节点样式
customClassstring-自定义根节点样式类
customLabelClassstring-自定义标签样式类
customValueClassstring-自定义值样式类

Events事件

事件名触发条件参数说明
cancel点击取消按钮或遮罩层关闭时-
change选中值变化时value: 选中的日期值
update:modelValue选中值变化并确认后newValue: 新的选中值
confirm点击确定按钮时value: 选中的日期值, type: 当前选择类型
open打开选择器时-
clear点击清空按钮时-

Methods方法

方法名参数返回值功能说明
open--打开时间选择器弹窗
close--关闭时间选择器弹窗

Slots插槽

插槽名作用域变量使用说明
default-自定义选择器内容,仅当withCell为false时有效
label-自定义左侧标签内容

多场景使用示例代码

1. 基础用法

vue
<template>
  <view class="calendar-demo">
    <wd-calendar 
      v-model="date" 
      label="选择日期" 
      placeholder="请选择日期"
      @change="handleChange"
    />
    <view class="result">选中的日期:{{ formatDate(date) }}</view>
  </view>
</template>

<script lang="ts" setup>
import { ref } from 'vue'
import { showToast } from '@/utils/toast'

// 基础日历选择器用法
const date = ref<number | null>(null)

// 格式化日期
const formatDate = (timestamp: number | null) => {
  if (!timestamp) return ''
  const date = new Date(timestamp)
  return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`
}

// 处理选择事件
const handleChange = (event: any) => {
  showToast(`选择了:${formatDate(event.value)}`)
}
</script>

<style scoped>
.calendar-demo {
  padding: 20rpx;
  display: flex;
  flex-direction: column;
  gap: 20rpx;
}

.result {
  font-size: 28rpx;
  color: #666;
  margin-top: 20rpx;
}
</style>

2. 不同类型选择

vue
<template>
  <view class="calendar-demo">
    <wd-calendar 
      v-model="singleDate" 
      type="date" 
      label="单个日期" 
    />
    <wd-calendar 
      v-model="dateRange" 
      type="daterange" 
      label="日期范围" 
    />
    <wd-calendar 
      v-model="dateTime" 
      type="datetime" 
      label="日期时间" 
    />
    <wd-calendar 
      v-model="week" 
      type="week" 
      label="周选择" 
    />
    <wd-calendar 
      v-model="month" 
      type="month" 
      label="月选择" 
    />
  </view>
</template>

<script lang="ts" setup>
import { ref } from 'vue'

// 不同类型的日历选择器
const singleDate = ref<number | null>(null)
const dateRange = ref<number[]>([])
const dateTime = ref<number | null>(null)
const week = ref<number | null>(null)
const month = ref<number | null>(null)
</script>

<style scoped>
.calendar-demo {
  padding: 20rpx;
  display: flex;
  flex-direction: column;
  gap: 20rpx;
}
</style>

3. 带快捷选项

vue
<template>
  <view class="calendar-demo">
    <wd-calendar 
      v-model="date" 
      label="带快捷选项" 
      :shortcuts="shortcuts"
      :on-shortcuts-click="handleShortcutsClick"
    />
  </view>
</template>

<script lang="ts" setup>
import { ref } from 'vue'
import dayjs from '@/utils/dayjs'

// 带快捷选项的日历选择器
const date = ref<number | null>(null)

// 快捷选项
const shortcuts = ref([
  { text: '今天' },
  { text: '昨天' },
  { text: '近7天' },
  { text: '近30天' }
])

// 处理快捷选项点击
const handleShortcutsClick = (event: any) => {
  const { index } = event
  const now = dayjs()
  let result: number | number[] = 0
  
  switch (index) {
    case 0: // 今天
      result = now.valueOf()
      break
    case 1: // 昨天
      result = now.subtract(1, 'day').valueOf()
      break
    case 2: // 近7天
      result = [now.subtract(6, 'day').valueOf(), now.valueOf()]
      break
    case 3: // 近30天
      result = [now.subtract(29, 'day').valueOf(), now.valueOf()]
      break
  }
  
  return result
}
</script>

<style scoped>
.calendar-demo {
  padding: 20rpx;
  display: flex;
  flex-direction: column;
  gap: 20rpx;
}
</style>

4. 自定义格式化和限制

vue
<template>
  <view class="calendar-demo">
    <wd-calendar 
      v-model="date" 
      label="自定义格式化和限制" 
      :min-date="minDate" 
      :max-date="maxDate"
      :formatter="formatter"
      :display-format="displayFormat"
    />
  </view>
</template>

<script lang="ts" setup>
import { ref } from 'vue'
import dayjs from '@/utils/dayjs'

// 自定义格式化和限制的日历选择器
const date = ref<number | null>(null)

// 最小日期(今天)
const minDate = ref(dayjs().startOf('day').valueOf())

// 最大日期(今天后30天)
const maxDate = ref(dayjs().add(30, 'day').endOf('day').valueOf())

// 日期格式化函数
const formatter = (day: any) => {
  const date = dayjs(day.date)
  const today = dayjs().startOf('day')
  const tomorrow = dayjs().add(1, 'day').startOf('day')
  
  if (date.isSame(today, 'day')) {
    day.text = '今天'
  } else if (date.isSame(tomorrow, 'day')) {
    day.text = '明天'
  }
  
  return day
}

// 自定义显示格式化
const displayFormat = (value: number | number[], type: string) => {
  if (!value) return ''
  return dayjs(value).format('YYYY年MM月DD日')
}
</script>

<style scoped>
.calendar-demo {
  padding: 20rpx;
  display: flex;
  flex-direction: column;
  gap: 20rpx;
}
</style>

5. 表单验证和清空功能

vue
<template>
  <view class="calendar-demo">
    <wd-form :model="form" :rules="rules" ref="formRef">
      <wd-calendar 
        v-model="form.date" 
        label="必填日期" 
        prop="date"
        clearable
        required
        error-message="请选择日期"
      />
      <view style="margin-top: 40rpx;">
        <wd-button type="primary" @click="handleSubmit">提交表单</wd-button>
      </view>
    </wd-form>
  </view>
</template>

<script lang="ts" setup>
import { ref, reactive } from 'vue'
import { showToast } from '@/utils/toast'

// 表单验证和清空功能
const formRef = ref<any>(null)
const form = reactive({
  date: null as number | null
})

// 表单验证规则
const rules = {
  date: [
    { required: true, message: '请选择日期', trigger: 'change' }
  ]
}

// 处理表单提交
const handleSubmit = async () => {
  const result = await formRef.value.validate()
  if (result.valid) {
    showToast('表单验证通过')
    console.log('表单数据:', form)
  }
}
</script>

<style scoped>
.calendar-demo {
  padding: 20rpx;
  display: flex;
  flex-direction: column;
  gap: 20rpx;
}
</style>

样式定制指南

1. 使用customStyle自定义样式

vue
<template>
  <wd-calendar 
    v-model="date" 
    label="自定义样式" 
    customStyle="margin: 20rpx;"
  />
</template>

<script lang="ts" setup>
import { ref } from 'vue'

const date = ref<number | null>(null)
</script>

2. 使用customClass自定义类名

vue
<template>
  <wd-calendar 
    v-model="date" 
    label="自定义类名" 
    customClass="my-calendar"
  />
</template>

<script lang="ts" setup>
import { ref } from 'vue'

const date = ref<number | null>(null)
</script>

<style scoped>
/* 注意:需要使用 ::v-deep 或 /deep/ 穿透 scoped 样式 */
:deep(.my-calendar) {
  background-color: #f5f7fa;
  border-radius: 8rpx;
  overflow: hidden;
}

:deep(.my-calendar .wd-calendar__cell) {
  padding: 15rpx 20rpx;
}
</style>

3. 自定义标签和值样式

vue
<template>
  <wd-calendar 
    v-model="date" 
    label="自定义标签和值样式" 
    customLabelClass="custom-label"
    customValueClass="custom-value"
  />
</template>

<script lang="ts" setup>
import { ref } from 'vue'

const date = ref<number | null>(null)
</script>

<style scoped>
/* 注意:需要使用 ::v-deep 或 /deep/ 穿透 scoped 样式 */
:deep(.custom-label) {
  font-weight: bold;
  color: #4D80F0;
}

:deep(.custom-value) {
  color: #34d19d;
  font-size: 32rpx;
}
</style>

注意事项

  1. modelValue类型:根据type属性的不同,modelValue的类型也不同:

    • 单值类型(date、datetime、week、month):number | null
    • 多值类型(dates):number[]
    • 范围类型(daterange、datetimerange、weekrange、monthrange):number[]
  2. 时间戳格式:所有日期值均使用13位时间戳格式

  3. minDate和maxDate

    • 默认为当前日期前后12个月
    • 可以通过这两个属性限制可选日期范围
  4. formatter函数:用于自定义日期显示,接收day对象,返回修改后的day对象

  5. displayFormat:用于自定义选择器显示的文本格式

  6. showConfirm

    • 默认为true,显示确定按钮
    • 为false时,选择后自动关闭并触发confirm事件
  7. safeAreaInsetBottom:在iPhone X等全面屏机型上,为true时会自动添加底部安全距离

  8. rootPortal:当页面中存在fixed定位元素时,可能会出现层级问题,设置rootPortal为true可以解决此问题

  9. clearable:设置为true时,会显示清空按钮,点击可清空已选值

  10. withCell

    • 默认为true,使用内置单元格样式
    • 为false时,可以通过default插槽自定义选择器内容
  11. 表单验证:结合wd-form使用时,需要设置prop属性和rules规则

  12. 快捷选项

    • shortcuts为快捷选项数组,每个选项需包含text属性
    • onShortcutsClick为快捷选项点击回调,需返回对应的时间戳或时间戳数组

📖 Released under the MIT License