vue3 日期组件

<template>
  <div class="r-datebox">
    <div class="current-date">
      <i class="iconfont icon-xiangzuo" @click="preMonth"></i>
      <span>{{ dateFormat(data.current, 'yyyy年MM月') }}</span>
      <i class="iconfont icon-xiangzuo next" @click="nextMonth"></i>
      <span class="go-today" @click="goToday">今天</span>
    </div>
    <div class="main-box">
      <div class="week">
        <div class="week-item" v-for="(item,index) in data.weeks" :key="index">{{ item.label }}</div>
      </div>
      <div class="date">
        <div class="date-item"
             :class="{pre : index < data.preCount}"
             v-for="(item,index) in data.dates" :key="index"
             @click="dateClick(item,index)">
          <div :class="{'date-item-value':data.dateIndex == index,today:isToday(item)}">
            {{ item.day }}
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script setup>
import {defineEmits, defineProps, onBeforeMount, reactive} from 'vue'

const props = defineProps({
  id: ''
})
const emit = defineEmits(['change']);

const data = reactive({
  weeks: [
    {label: '日', value: 0},
    {label: '一', value: 1},
    {label: '二', value: 2},
    {label: '三', value: 3},
    {label: '四', value: 4},
    {label: '五', value: 5},
    {label: '六', value: 6},
  ],
  current: new Date(),
  dateIndex: 0,
  preCount: 0,
  dates: []
})

const goToday = () => {
  data.current = new Date()
  initDate()
}

/** 判断是否是当前日期 */
const isToday = ({date}) => {
  let itemDateStr = dateFormat(date, 'YYYY-MM-dd')
  let todayDateStr = dateFormat(Date.now(), 'YYYY-MM-dd')
  return itemDateStr === todayDateStr
}

/** 日期点击 **/
const dateClick = (item, index) => {
  data.dateIndex = index;
  emit('change', dateFormat(item.date), item.date)
}

/** 上一个月 **/
const preMonth = () => {
  let y = data.current.getFullYear()
  let m = data.current.getMonth()
  if (m == 0) {
    m = 11
    y -= 1
  } else {
    m -= 1
  }

  data.current.setFullYear(y)
  data.current.setMonth(m)

  initDate()
}

/** 下一个月 **/
const nextMonth = () => {
  let y = data.current.getFullYear()
  let m = data.current.getMonth()
  if (m == 11) {
    m = 0
    y += 1
  } else {
    m += 1
  }

  data.current.setFullYear(y)
  data.current.setMonth(m)

  initDate()
}

/** 获取上一个月,返回年月 **/
const getPreYearAndMonth = () => {
  let y = data.current.getFullYear()
  let m = data.current.getMonth()
  if (m == 0) {
    m = 11
    y = y - 1
  } else {
    m = m - 1
  }

  return [y, m]
}

/** 页面加载完成,初始化日期 **/
const initDate = () => {
  let y = data.current.getFullYear()
  let m = data.current.getMonth()
  getDates(y, m)
}

/** 渲染日期 **/
const getDates = (y, m) => {
  let length = getCountByMonth(y, m)
  data.dates = Array.from({length}, (_, i) => ({
    day: i + 1,
    date: new Date(y, m, i + 1)
  }))

  //填充最前面的日期格子
  getPreDays(y, m)
}

/** 填充最前面的日期格子 **/
const getPreDays = (y, m) => {
  //获取第一天星期几
  let week = getFirstDayWeek(y, m)
  //如果月份第一天不是周天,则需要向前填充日期
  if (week != 0) {
    let list = []
    //获取上月总共天数
    let preMonthCount = getCountByMonth(y, m - 1)
    let end = preMonthCount - week
    let pre = getPreYearAndMonth()
    while (preMonthCount > end) {
      list.unshift({
        day: preMonthCount,
        date: new Date(pre[0], pre[1], preMonthCount)
      })
      preMonthCount--
    }

    data.preCount = list.length
    data.dates.unshift(...list)

    //获取当前日期所在的索引值
    let d = new Date()
    if (d.getFullYear() == y && d.getMonth() == m) {
      data.dateIndex = d.getDate() + week - 1
    } else {
      data.dateIndex = -1
    }
  }
}

/** 获取某年某月总共天数 **/
const getCountByMonth = (y, m) => {
  return new Date(y, m + 1, 0).getDate()
}

/** 获取某年某月第一天星期几 **/
const getFirstDayWeek = (y, m) => {
  return new Date(y, m, 1).getDay()
}

const dateFormat = (date, format) => {
  if (date) {
    date = date instanceof Date ? date : new Date(date);
    let o = {
      "M+": date.getMonth() + 1,                 //月份
      "d+": date.getDate(),                    //日
      "h+": date.getHours(),                   //小时
      "m+": date.getMinutes(),                 //分
      "s+": date.getSeconds(),                 //秒
      "q+": Math.floor((date.getMonth() + 3) / 3), //季度
      "S": date.getMilliseconds()             //毫秒
    };

    format = (format || 'yyyy-MM-dd hh:mm:ss').replace(/y+/i, date.getFullYear());
    for (let i in o) format = format.replace(new RegExp('(' + i + ')'), ('0' + o[i]).slice(-2));
    return format;
  }
  return '';
}

onBeforeMount(() => {
  initDate()
})
</script>
<style scoped lang="scss">
.r-datebox {
  font-size: var(--content-font-size);
  color: #555;
  padding: 10px;
  width: calc(100% - 20px);

  .current-date {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--word-active-color);
    margin-bottom: 20px;
    position: relative;

    i {
      cursor: pointer;

      &.next {
        transform: rotate(180deg);
      }
    }

    .go-today {
      position: absolute;
      right: 20px;
      cursor: pointer;
    }
  }

  .main-box {
    .week {
      display: flex;
      margin-bottom: 10px;

      .week-item {
        color: var(--word-active-color);
        width: calc(100% / 7);
        text-align: center;
        font-weight: 700;
      }
    }

    .date {
      display: flex;
      flex-wrap: wrap;

      .date-item {
        display: flex;
        align-items: center;
        justify-content: center;
        width: calc(100% / 7);
        height: 30px;
        line-height: 30px;
        text-align: center;
        cursor: pointer;
        color: var(--word-active-color);

        .date-item-value {
          position: relative;
          width: 30px;
          height: 30px;
          background: var(--border-color-3);
          border-radius: 50%;
          color: #fff;
        }

        .today {
          position: relative;
          width: 30px;
          height: 30px;

          &:after {
            position: absolute;
            content: 'Today';
            transform: scale(.5);
            color: var(--box-bg-color-2);
            right: 0;
            top: -6px;
            width: 8px;
            height: 8px;
          }
        }

        &.pre {
          color: #bdbdbd;
        }

        //&:hover, &.active {
        //  background: var(--bg-blue-color);
        //  color: #fff;
        //  border-radius: 8px;
        //}

      }
    }
  }
}
</style>

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

roffer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值