基于 Element Plus 的增强型日期区间选择组件

5 阅读3分钟

基于 Element Plus 的增强型日期区间选择组件技术文档

一、组件概述

本组件基于 Element Plusel-date-pickerdaterange 模式)进行二次封装,实现了以下增强能力:

image.png

✅ 功能特性

  • 日期区间选择(双向绑定)
  • 最小日期限制(不可选历史日期)
  • 表单必填校验
  • 外部错误状态联动
  • 自定义日期单元格渲染
  • 显示“班 / 休”角标(支持节假日 & 调休)
  • 选中态样式增强(高亮红色)
  • 方法暴露(支持父组件调用)

二、适用场景

适用于以下业务:

  • 报单时间选择
  • 交易时间筛选
  • 工单 / 日志时间区间
  • 需要展示“工作日/休息日”的场景

三、核心实现结构

1️⃣ 基础组件结构

<el-date-picker
  v-model="dateRange"
  type="daterange"
  range-separator="至"
  start-placeholder="开始日期"
  end-placeholder="结束日期"
  value-format="YYYY-MM-DD"
  format="YYYY-MM-DD"
  :disabled="disabled"
  :min-date="minDateObj"
  :disabled-date="disabledDate"
  :class="{ 'is-error': hasError || internalError }"
  @change="handleDateChange"
>

四、核心功能拆解


4.1 双向绑定(v-model 封装)

const dateRange = computed({
  get: () => props.modelValue || [],
  set: (val) => {
    emit('update:modelValue', val)

    if (props.required) {
      internalError.value = !(val && val[0] && val[1])
    }
  }
})
✅ 作用:
  • 实现 v-model 透传
  • 内部自动触发表单校验
  • 解耦父子组件数据

4.2 最小日期限制

const minDateObj = computed(() => {
  if (!props.minDate) return null
  return dayjs(props.minDate)
})
const disabledDate = (date) => {
  if (!minDateObj.value) return false

  return (
    dayjs(date).isSame(minDateObj.value, 'day') ||
    dayjs(date).isBefore(minDateObj.value, 'day')
  )
}
✅ 实现效果:
  • 禁止选择 minDate 及之前日期
  • 强制用户选择未来时间

4.3 日期选择回调

const handleDateChange = (val) => {
  emit('change', {
    startDate: val?.[0] || null,
    endDate: val?.[1] || null
  })
}
✅ 输出结构:
{
  startDate: '2026-03-01',
  endDate: '2026-03-10'
}

4.4 表单校验机制

内部错误状态
const internalError = ref(false)
外部联动
watch(() => props.hasError, (newVal) => {
  internalError.value = newVal
}, { immediate: true })
✅ 支持:
  • 父组件控制错误
  • 子组件自动校验

五、日期单元格自定义渲染(核心亮点)

5.1 插槽结构

<template #default="cell">

5.2 自定义内容

<div class="el-date-table-cell">
  <span>{{ cell.text }}</span>

  <span class="corner-tag">
    {{ getDayType(cell.dayjs) ? '休' : '班' }}
  </span>
</div>

六、工作日 / 休息日判断逻辑

6.1 节假日库(核心)

import ChineseDays from 'chinese-days'

6.2 判断逻辑

const getDayType = (date) => {
  const dateStr = date.format('YYYY-MM-DD')

  try {
    if (ChineseDays.isWorkday(dateStr)) return false
    if (ChineseDays.isHoliday(dateStr)) return true
  } catch (e) {
    console.warn('节假日库异常:', e)
  }

  const day = date.day()
  return day === 0 || day === 6
}

✅ 优先级说明

判断方式优先级
调休补班(isWorkday)最高
法定节假日(isHoliday)次高
周末判断兜底

七、样式系统设计


7.1 角标样式

.corner-tag {
  position: absolute;
  right: 2px;
  bottom: 2px;
  font-size: 10px;
}
班 / 休颜色:
.tag-work {
  color: #00B42A;
}

.tag-rest {
  color: #FF7D00;
}

7.2 选中态优化(重点)

单个日期
.is-selected {
  background-color: #f56c6c;
}
区间范围
.is-in-range {
  background-color: rgba(245, 108, 108, 0.15);
}
起止点
.start-date,
.end-date {
  background-color: #f56c6c;
}

7.3 错误状态样式

.is-error {
  border-color: #f56c6c;
}

八、组件对外能力(defineExpose)


8.1 获取选中日期

getSelectedDates()

返回:

{
  startDate,
  endDate
}

8.2 设置日期

setDates(['2026-01-01', '2026-01-10'])

8.3 校验方法

validate()

返回:

{ valid: true }

{ valid: false, message: '请选择日期范围' }

8.4 重置校验

resetValidation()

九、关键设计亮点 ⭐


✅ 1. UI 与业务解耦

  • 选择器只负责展示
  • 校验与数据通过 props + emit 控制

✅ 2. 可扩展性强

可扩展:

  • 最大选择范围限制(如 1 年)
  • 禁止未来日期
  • 多日历联动

✅ 3. 用户体验优化

  • 直观“班 / 休”提示
  • 红色高亮增强可读性
  • 错误态清晰反馈

✅ 4. 高容错设计

  • 节假日库异常自动降级
  • 不影响主流程

十、可扩展方向


🔧 1. 增加“最大跨度限制”

Math.abs(dayjs(end).diff(start, 'day')) <= 365

🔧 2. 支持多语言

  • “班 / 休” → Work / Rest

🔧 3. 支持后端节假日配置

替换:

ChineseDays

为:

API 获取

🔧 4. 表单集成(el-form)

结合:

<el-form-item prop="dateRange">

十一、总结

该组件实现了一个企业级日期选择器增强方案

🎯 核心能力

  • 精准日期控制
  • 节假日识别
  • 表单校验
  • 高可扩展性

🚀 适用于

  • 金融系统
  • OA 系统
  • 数据分析平台