乐趣区

关于前端:vue手写日历

<template>
  <div class="my-calendar-container">
    <div class="top-title">
      <Icon name="arrow-left" @click="pre" />
      <span>{{nowMonth}} {{nowYear}}</span>
      <Icon name="arrow" @click="next" />
    </div>
    <div class="weeks">
      <span>M</span>
      <span>T</span>
      <span>W</span>
      <span>T</span>
      <span>F</span>
      <span>S</span>
      <!-- 印尼周日放到最初一天 -->
      <span>S</span>
    </div>
    <div class="line"></div>
    <div class="day-box">
      <span v-for="(item,index) in days" :key="index" :style="getStyle(item)" @click="handleClick(item)">{{item.day}}<i v-if="index%6 ===0" class="point-box" /></span>
    </div>
  </div>
</template>

<script setup lang="ts">
  import {ref} from 'vue'
  import {Icon} from 'vant';
  const nowDate = new Date()
  let nowYear = nowDate.getFullYear()
  let nowMonth = nowDate.getMonth() + 1
  const nowDay = nowDate.getDate()
  
  let days: any = ref([])
  // 获取日期展现列表
  const getDaysList = (year: number, month: number,activeDay:number) => {days.value = []
    const nowMonthCount = new Date(year, month, 0).getDate() // 获取本月有多少天
    const preMonthCount = new Date(month > 0 ? year : (year - 1), month > 0 ? (month - 1) : 12, 0).getDate() // 获取上月有多少天
    const monthOne = getMonthOne(year, month)
    // 补全上个月
    if (monthOne > 1) {for (let i = monthOne - 2; i >= 0; i--) {days.value.push({day: preMonthCount - i,disabled: true,activeDay:false})
      }
    }
    // 当月
    for (let i = 0; i < nowMonthCount; i++) {days.value.push({day: i + 1,disabled: false,activeDay: activeDay === (i+1)})
    }
    // 补全下月
    if (days.value.length % 7) {for (let i = 0; i < days.value.length % 7; i++) {days.value.push({day: i + 1,disabled: true,activeDay:false})
      }
    }
  }
  // 上个月
  const pre = () => {nowYear = nowMonth===1? (nowYear - 1) : nowYear
    nowMonth = nowMonth===1? 12 : (nowMonth-1)
    getDaysList(nowYear, nowMonth,1)
  }
  // 下个月
  const next = () => {nowYear = nowMonth===12? (nowYear + 1) : nowYear
    nowMonth = nowMonth===12? 1 : (nowMonth+1)
    getDaysList(nowYear, nowMonth,1)
  }
  const getStyle = (item:any) => {if(item.activeDay) {return {background: '#D41367',color:'#fff'}
    }else if(item.disabled) {return {background: '#FFF',color:'#C7C7C7'}
    }else {return {background: '#FFF',color:'#101010'}
    }
  }

  // 点击日期
  const handleClick = (item:any) => {if(!item.disabled) {getDaysList(nowYear,nowMonth,item.day)
     }
  }
  // 获取某月 1 号星期几
  const getMonthOne = (year: number, month: number) => new Date(year, month - 1, 1).getDay() % 7 // 星期天第 7 天
  getDaysList(nowYear, nowMonth,nowDay)
</script>

<style lang="scss" scoped>
  .my-calendar-container {
    padding: 24px;
    background: #fff;
    padding-bottom: 15px;
    // width: 100%;
    // height: 307px;

    .top-title {

      display: flex;
      justify-content: space-between;
      align-items: center;

      ::v-deep .van-icon {font-size: 18px;}

      &>span {
        font-size: 14px;
        font-family: Lato-Bold, Lato;
        font-weight: bold;
        color: #101010;
      }
    }

    .weeks {
      width: 100%;
      margin-top: 26px;
       display: grid;
      grid-template-columns: repeat(7, calc(100%/7));
      text-align: center;
      &>span {
        text-align: center;
        font-size: 9px;
        font-family: Lato-Regular, Lato;
        font-weight: 400;
        color: #101010;
      }
    }

    .line {
      margin-top: 7px;
      height: 1px;
      background-color: #E5E5E5;
    }

    .day-box {
      display: grid;
      grid-template-columns: repeat(7, calc(100%/7));

      &>span {
        position: relative;
        width: 29px;
        height: 29px;
        margin: 7px auto;
        // background: #D41367;
        line-height: 29px;
        text-align: center;
        border-radius: 50%;
        font-size: 13px;
        font-family: Lato-Regular, Lato;

        i.point-box {
          position: absolute;
          width: 5px;
          height: 5px;
          bottom: 0;
          left: 50%;
          transform: translateX(-50%);
          border-radius: 50%;
          background-color: #D41367;
        }
      }
    }
  }
</style>
退出移动版