使用Vue3 + Elementplus + Day.js 实现日期选择器(包括日、周、月、年、自定义) - 附完整示例

**Day.js:**是一个极简的JavaScript库,可以为现代浏览器解析、验证、操作和显示日期和时间。

目录

效果

一、介绍

1、官网:Day.js中文网

[2、官方文档 - 中文网:安装 | Day.js中文网](#2、官方文档 - 中文网:安装 | Day.js中文网)

二、准备工作

1、安装依赖包

2、示例版本

三、使用步骤

1、在单页面引入 'dayjs'

2、具体使用(以默认日选择器举例)

四、完整示例


效果

一、介绍

1、官网: Day.js中文网

Day.js中文网Day.js是一个极简的JavaScript库,可以为现代浏览器解析、验证、操作和显示日期和时间。https://dayjs.fenxianglu.cn/

2、官方文档 - 中文网:安装 | Day.js中文网

安装 | Day.js中文网Day.js是一个极简的JavaScript库,可以为现代浏览器解析、验证、操作和显示日期和时间。https://dayjs.fenxianglu.cn/category/

二、准备工作

1、安装依赖包

复制代码
# 选择一个你喜欢的包管理器

# npm
$ npm install dayjs

# cnpm 
$ cnpm install dayjs -S

# yarn
$ yarn add dayjs

# pnpm
$ pnpm install dayjs

注:也可以通过浏览器的 script 标签导入 CDN 文件使用

安装 | Day.js中文网

2、示例版本

复制代码
"dayjs": "^1.11.19",

三、使用步骤

1、在单页面引入 'dayjs'

复制代码
import type { Dayjs } from 'dayjs'
import dayjs from 'dayjs'
import isoWeek from 'dayjs/plugin/isoWeek'
import utc from 'dayjs/plugin/utc'

// 扩展dayjs功能
dayjs.extend(isoWeek)
dayjs.extend(utc)

2、具体使用(以默认日选择器举例)

复制代码
const dayStart = dayjs(selectDays.value).startOf('day')
const dayEnd = dayjs(selectDays.value).endOf('day')

......详见完整示例

四、完整示例

复制代码
<template>
  <div class="container">
    <!-- 日期选择区域 -->
    <el-space direction="vertical" size="large">
      <el-space>
        <!-- 日期类型选择器 -->
        <el-radio-group v-model="dateType" @change="handleDateTypeChange">
          <el-radio-button label="日" />
          <el-radio-button label="周" />
          <el-radio-button label="月" />
          <el-radio-button label="年" />
          <el-radio-button label="自定义" />
        </el-radio-group>

        <!-- 日选择器 -->
        <el-date-picker
          v-if="dateType === '日'"
          v-model="selectDays"
          type="date"
          format="YYYY-MM-DD"
          placeholder="请选择日期"
          @change="dateChange"
          :disabled-date="disabledDate"
        />

        <!-- 周选择器-->
        <el-date-picker
          v-if="dateType === '周'"
          v-model="selectWeeks"
          type="week"
          format="GGGG年第ww周"
          value-format="YYYY-MM-DD"
          placeholder="请选择周"
          @change="dateChange"
          :disabled-date="disabledDate"
        />

        <!-- 月选择器 -->
        <el-date-picker
          v-if="dateType === '月'"
          v-model="selectMonths"
          type="month"
          format="YYYY-MM"
          value-format="YYYY-MM"
          placeholder="请选择月"
          @change="dateChange"
          :disabled-date="disabledDate"
        />

        <!-- 年选择器 -->
        <el-date-picker
          v-if="dateType === '年'"
          v-model="selectYears"
          type="year"
          format="YYYY"
          value-format="YYYY"
          placeholder="请选择年"
          @change="dateChange"
          :disabled-date="disabledDate"
        />

        <!-- 自定义日期范围选择器,默认空,限制≤7天 -->
        <el-date-picker
          v-if="dateType === '自定义'"
          v-model="selectRange"
          type="daterange"
          format="YYYY-MM-DD"
          value-format="YYYY-MM-DD"
          :placeholder="['请选择开始日期', '请选择结束日期']"
          @change="handleCustomDateChange"
          :disabled-date="disabledDate"
        />
      </el-space>

      <!-- 选择结果展示区域 -->
      <div class="selected-date-display">
        <div class="display-label">当前选择:</div>
        <div class="display-value">{{ selectedDateText }}</div>
      </div>
    </el-space>
  </div>
</template>

<script setup lang="ts" name="dateSelector">
import type { Dayjs } from 'dayjs'
import dayjs from 'dayjs'
import isoWeek from 'dayjs/plugin/isoWeek'
import utc from 'dayjs/plugin/utc'
import { ElMessage } from 'element-plus'
import { computed } from 'vue'

// 扩展dayjs功能
dayjs.extend(isoWeek)
dayjs.extend(utc)

// 日期选择相关
const dateType = ref<string>('日') // 默认日选择器
const selectDays = ref<Dayjs | null>(dayjs()) // 日选择器-默认当日
const selectWeeks = ref<string | null>(dayjs().startOf('isoWeek').format('YYYY-MM-DD')) // 周选择器-默认当周
const selectMonths = ref<string | null>(dayjs().format('YYYY-MM')) // 月选择器-默认当月
const selectYears = ref<string | null>(dayjs().format('YYYY')) // 年选择器-默认当年
const selectRange = ref<[string, string] | null>(null) // 自定义日期范围
const startTime = ref<string | null>(null) // 开始时间(UTC格式)
const endTime = ref<string | null>(null) // 结束时间(UTC格式)

// 禁用未来日期
const disabledDate = (time: Date) => {
  return time.getTime() > Date.now()
}

// 初始化时间范围
const initTimeRange = () => {
  switch (dateType.value) {
    case '日':
      if (selectDays.value) {
        const dayStart = dayjs(selectDays.value).startOf('day')
        const dayEnd = dayjs(selectDays.value).endOf('day')
        startTime.value = dayStart.utc().format('YYYY-MM-DDTHH:mm:ss[Z]')
        endTime.value = dayEnd.utc().format('YYYY-MM-DDTHH:mm:ss[Z]')
      } else {
        startTime.value = null
        endTime.value = null
      }
      break
    case '周':
      if (selectWeeks.value) {
        const weekStart = dayjs(selectWeeks.value).startOf('day')
        const weekEnd = dayjs(selectWeeks.value).endOf('isoWeek').endOf('day')
        startTime.value = weekStart.utc().format('YYYY-MM-DDTHH:mm:ss[Z]')
        endTime.value = weekEnd.utc().format('YYYY-MM-DDTHH:mm:ss[Z]')
      } else {
        const currentWeekStart = dayjs().startOf('isoWeek').startOf('day')
        const currentWeekEnd = dayjs().endOf('isoWeek').endOf('day')
        startTime.value = currentWeekStart.utc().format('YYYY-MM-DDTHH:mm:ss[Z]')
        endTime.value = currentWeekEnd.utc().format('YYYY-MM-DDTHH:mm:ss[Z]')
      }
      break
    case '月':
      if (selectMonths.value) {
        const monthStart = dayjs(selectMonths.value).startOf('month').startOf('day')
        const monthEnd = dayjs(selectMonths.value).endOf('month').endOf('day')
        startTime.value = monthStart.utc().format('YYYY-MM-DDTHH:mm:ss[Z]')
        endTime.value = monthEnd.utc().format('YYYY-MM-DDTHH:mm:ss[Z]')
      } else {
        const currentMonthStart = dayjs().startOf('month').startOf('day')
        const currentMonthEnd = dayjs().endOf('month').endOf('day')
        startTime.value = currentMonthStart.utc().format('YYYY-MM-DDTHH:mm:ss[Z]')
        endTime.value = currentMonthEnd.utc().format('YYYY-MM-DDTHH:mm:ss[Z]')
      }
      break
    case '年':
      if (selectYears.value) {
        const yearStart = dayjs(`${selectYears.value}-01-01`).startOf('day').utc()
        const yearEnd = dayjs(`${selectYears.value}-12-31`).endOf('day').utc()
        startTime.value = yearStart.format('YYYY-MM-DDTHH:mm:ss[Z]')
        endTime.value = yearEnd.format('YYYY-MM-DDTHH:mm:ss[Z]')
      } else {
        const currentYear = dayjs().format('YYYY')
        const yearStart = dayjs(`${currentYear}-01-01`).startOf('day').utc()
        const yearEnd = dayjs(`${currentYear}-12-31`).endOf('day').utc()
        startTime.value = yearStart.format('YYYY-MM-DDTHH:mm:ss[Z]')
        endTime.value = yearEnd.format('YYYY-MM-DDTHH:mm:ss[Z]')
      }
      break
    case '自定义':
      startTime.value = null
      endTime.value = null
      break
  }
}

// 自定义日期范围变化处理(限制≤7天)
const handleCustomDateChange = (date: [string, string] | null) => {
  if (!date) {
    startTime.value = null
    endTime.value = null
    selectRange.value = null
    return
  }

  const startDay = dayjs(date[0])
  const endDay = dayjs(date[1])
  const dayDiff = endDay.diff(startDay, 'day')

  if (dayDiff > 7) {
    ElMessage.error('自定义日期范围不能超过7天')
    selectRange.value = null
    dateChange(null)
  } else {
    dateChange(date)
  }
}

// 日期变化统一处理
const dateChange = (date: any) => {
  switch (dateType.value) {
    case '日':
      if (date) {
        const selectedDay = dayjs(date)
        startTime.value = selectedDay.startOf('day').utc().format('YYYY-MM-DDTHH:mm:ss[Z]')
        endTime.value = selectedDay.endOf('day').utc().format('YYYY-MM-DDTHH:mm:ss[Z]')
      } else {
        startTime.value = null
        endTime.value = null
      }
      break
    case '周':
      if (date) {
        const weekStart = dayjs(date).startOf('day')
        const weekEnd = dayjs(date).endOf('isoWeek').endOf('day')
        startTime.value = weekStart.utc().format('YYYY-MM-DDTHH:mm:ss[Z]')
        endTime.value = weekEnd.utc().format('YYYY-MM-DDTHH:mm:ss[Z]')
      } else {
        const currentWeekStart = dayjs().startOf('isoWeek').startOf('day')
        const currentWeekEnd = dayjs().endOf('isoWeek').endOf('day')
        startTime.value = currentWeekStart.utc().format('YYYY-MM-DDTHH:mm:ss[Z]')
        endTime.value = currentWeekEnd.utc().format('YYYY-MM-DDTHH:mm:ss[Z]')
      }
      break
    case '月':
      if (date) {
        const monthStart = dayjs(date).startOf('month').startOf('day')
        const monthEnd = dayjs(date).endOf('month').endOf('day')
        startTime.value = monthStart.utc().format('YYYY-MM-DDTHH:mm:ss[Z]')
        endTime.value = monthEnd.utc().format('YYYY-MM-DDTHH:mm:ss[Z]')
      } else {
        const currentMonthStart = dayjs().startOf('month').startOf('day')
        const currentMonthEnd = dayjs().endOf('month').endOf('day')
        startTime.value = currentMonthStart.utc().format('YYYY-MM-DDTHH:mm:ss[Z]')
        endTime.value = currentMonthEnd.utc().format('YYYY-MM-DDTHH:mm:ss[Z]')
      }
      break
    case '年':
      if (date) {
        const yearStart = dayjs(`${date}-01-01`).startOf('day').utc()
        const yearEnd = dayjs(`${date}-12-31`).endOf('day').utc()
        startTime.value = yearStart.format('YYYY-MM-DDTHH:mm:ss[Z]')
        endTime.value = yearEnd.format('YYYY-MM-DDTHH:mm:ss[Z]')
      } else {
        const currentYear = dayjs().format('YYYY')
        const yearStart = dayjs(`${currentYear}-01-01`).startOf('day').utc()
        const yearEnd = dayjs(`${currentYear}-12-31`).endOf('day').utc()
        startTime.value = yearStart.format('YYYY-MM-DDTHH:mm:ss[Z]')
        endTime.value = yearEnd.format('YYYY-MM-DDTHH:mm:ss[Z]')
      }
      break
    case '自定义':
      if (date && Array.isArray(date) && date.length === 2) {
        const startDate = dayjs(date[0])
        const endDate = dayjs(date[1])
        startTime.value = startDate.startOf('day').utc().format('YYYY-MM-DDTHH:mm:ss[Z]')
        endTime.value = endDate.endOf('day').utc().format('YYYY-MM-DDTHH:mm:ss[Z]')
      } else {
        startTime.value = null
        endTime.value = null
      }
      break
  }
}

// 日期类型切换处理
const handleDateTypeChange = (value: string) => {
  dateType.value = value

  switch (value) {
    case '日':
      selectDays.value = dayjs()
      selectWeeks.value = null
      selectMonths.value = null
      selectYears.value = null
      selectRange.value = null
      initTimeRange()
      break
    case '周':
      selectDays.value = null
      selectWeeks.value = dayjs().startOf('isoWeek').format('YYYY-MM-DD')
      selectMonths.value = null
      selectYears.value = null
      selectRange.value = null
      initTimeRange()
      break
    case '月':
      selectDays.value = null
      selectWeeks.value = null
      selectMonths.value = dayjs().format('YYYY-MM')
      selectYears.value = null
      selectRange.value = null
      initTimeRange()
      break
    case '年':
      selectDays.value = null
      selectWeeks.value = null
      selectMonths.value = null
      selectYears.value = dayjs().format('YYYY')
      selectRange.value = null
      initTimeRange()
      break
    case '自定义':
      selectDays.value = null
      selectWeeks.value = null
      selectMonths.value = null
      selectYears.value = null
      selectRange.value = null
      startTime.value = null
      endTime.value = null
      break
  }
}

// 计算当前选择的日期文本
const selectedDateText = computed(() => {
  switch (dateType.value) {
    case '日':
      return selectDays.value ? `日:${dayjs(selectDays.value).format('YYYY-MM-DD')}` : '日:未选择'
    case '周':
      if (selectWeeks.value) {
        const weekStart = dayjs(selectWeeks.value).format('YYYY-MM-DD')
        const weekEnd = dayjs(selectWeeks.value).endOf('isoWeek').format('YYYY-MM-DD')
        return `周:${weekStart} 至 ${weekEnd}(${dayjs(selectWeeks.value).format('GGGG年第ww周')})`
      }
      return '周:未选择'
    case '月':
      return selectMonths.value ? `月:${selectMonths.value}` : '月:未选择'
    case '年':
      return selectYears.value ? `年:${selectYears.value}` : '年:未选择'
    case '自定义':
      if (selectRange.value && selectRange.value.length === 2) {
        return `自定义:${selectRange.value[0]} 至 ${selectRange.value[1]}`
      }
      return '自定义:未选择'
    default:
      return '未选择'
  }
})

// 挂载时初始化
onMounted(() => {
  initTimeRange()
})
</script>

<style scoped>
.container {
  padding: 100px;
}

.selected-date-display {
  margin-top: 20px;
  padding: 12px 16px;
  background: #f5f7fa;
  border-radius: 8px;
  display: flex;
  align-items: center;
}

.display-label {
  font-weight: 600;
  color: #303133;
  margin-right: 8px;
}

.display-value {
  color: #606266;
  font-size: 14px;
}
</style>
相关推荐
摘星编程1 小时前
OpenHarmony + RN:Placeholder文本占位
javascript·react native·react.js
a1117762 小时前
医院挂号预约系统(开源 Fastapi+vue2)
前端·vue.js·python·html5·fastapi
0思必得02 小时前
[Web自动化] Selenium处理iframe和frame
前端·爬虫·python·selenium·自动化·web自动化
计算机毕设VX:Fegn08952 小时前
计算机毕业设计|基于springboot + vue蛋糕店管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
行走的陀螺仪4 小时前
uni-app + Vue3编辑页/新增页面给列表页传参
前端·vue.js·uni-app
摘星编程4 小时前
React Native + OpenHarmony:Spinner旋转加载器
javascript·react native·react.js
We་ct5 小时前
LeetCode 205. 同构字符串:解题思路+代码优化全解析
前端·算法·leetcode·typescript
2301_812731415 小时前
CSS3笔记
前端·笔记·css3
ziblog5 小时前
CSS3白云飘动动画特效
前端·css·css3
越努力越幸运5085 小时前
CSS3学习之网格布局grid
前端·学习·css3