使用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>
相关推荐
冴羽2 小时前
2025 年 HTML 年度调查报告亮点速览!
前端·javascript·html
张元清2 小时前
浏览器硬导航优化:提升用户体验的关键
前端·javascript·面试
程序员爱钓鱼2 小时前
Node.js 编程实战:博客系统 —— 用户注册登录与文章管理
前端·后端·node.js
xkxnq2 小时前
第二阶段:Vue 组件化开发(第 23天)
前端·javascript·vue.js
zcz16071278212 小时前
nmcli常见操作
前端·chrome
晴栀ay2 小时前
JS的超集——TypeScript
前端·react.js·typescript
EndingCoder2 小时前
高级类型:联合类型和类型别名
linux·服务器·前端·ubuntu·typescript
廖若星辰LTY2 小时前
网页端获取用户剪贴板内容
javascript
yyf198905252 小时前
Vue.js:现代前端开发的渐进式框架
vue.js