vue3 自定义日历组件

638 阅读1分钟

组件的模板内容

<template>
  <div class="calender_wrapper">
    <el-scrollbar>
      <div class="month_box_wrapper">
        <div class="month_box" v-for="item in allMonthObj.allMonthList">
          <h3 class="month_tit">{{ item.month }}月</h3>
          <table class="tb">
            <!--星期几;-->
            <tr class="tr tit">
              <td></td>
              <td></td>
              <td></td>
              <td></td>
              <td></td>
              <td></td>
              <td style="color: #e51f1f"></td>
              <td style="color: #e51f1f"></td>
            </tr>
            <!--日期展示;-->
            <tr class="tr" v-for="itemTr in item.dayList">
              <td class="week_num">{{ itemTr.week }}</td>
              <td v-for="itemTd in itemTr.weekData" :class="{ current_month: itemTd.currentMonth, today: itemTd.today }">
                <template v-if="itemTd.today">
                  <span class="today_text">{{ itemTd.date }}</span>
                </template>
                <template v-else>{{ itemTd.date }}</template>
              </td>
            </tr>
          </table>
        </div>
      </div>
    </el-scrollbar>
  </div>
</template>

组件js代码实现

<script lang="ts" setup>
import { reactive, watch } from 'vue';

interface props {
  year: number | string;
  monthList: number[];
}
let propsData = defineProps<props>();
const { year, monthList } = propsData;

let allMonthObj: any = reactive({
  allMonthList: [],
});

/**
 * 生成日历;
 */
const getcalendar = (year: number, month: number) => {
  let allDayList: any[] = [];
  year = year ? year : new Date().getFullYear();
  //month是0开始到11结束的,获取当前月份必须加1
  month = month ? month : new Date().getMonth() + 1;
  let last = new Date(year, month - 1, 0);
  let lastdate = last.getDate(); //获取上个月的最大日期
  let lastday = last.getDay(); //获取上个月最大日期的星期几
  let months = new Date(year, month, 0);
  let Maxdate = months.getDate(); //获取这个月最大的日期
  let today = new Date().getDate();
  let thisyear = new Date().getFullYear();
  let thismonth = new Date().getMonth() + 1;
  //获取上个月在这个月份中存在的最后日期
  var remainlastdate = lastdate - lastday + 1;
  var t = 1;
  var week = 1;
  // 首行数据解析;
  allDayList.push({ week: null, weekData: [] });
  for (var g = 1; g <= 7; g++) {
    if (g <= lastday) {
      allDayList[0].weekData.push({ date: remainlastdate++, currentMonth: false });
    } else {
      if (thisyear == year && thismonth == month && today == t) {
        allDayList[0].weekData.push({ date: t++, today: true });
      } else {
        allDayList[0].weekData.push({ date: t++, currentMonth: true });
      }
      allDayList[0].week = getYearWeek(year, month.toString(), t - 1);
    }
  }
  var remainlastday = 7 - lastday + 1;
  var nextMonthday = 1; //下一个月份的开始日期
  for (var i = 1; i <= 5; i++) {
    allDayList.push({ week: null, weekData: [] });
    for (var j = 0; j < 7; j++) {
      if (remainlastday <= Maxdate) {
        if (thisyear == year && thismonth == month && today == remainlastday) {
          allDayList[i].weekData.push({ date: remainlastday++, today: true });
          allDayList[i].week = getYearWeek(year, month.toString(), remainlastday - 1);
        } else {
          allDayList[i].weekData.push({ date: remainlastday++, currentMonth: true });
          allDayList[i].week = getYearWeek(year, month.toString(), remainlastday - 1);
        }
      } else {
        allDayList[i].weekData.push({ date: nextMonthday++, currentMonth: false });
        month < 12 && (allDayList[i].week = getYearWeek(year, (month + 1).toString(), nextMonthday - 1));
      }
    }
  }
  return allDayList;
};
/**
 * 生成每个月的日历;
 */
const getMonthscalendar = (year: number) => {
  monthList.map((item) => {
    allMonthObj.allMonthList.push({ month: item, dayList: getcalendar(year, item) });
  });
};

/**
 * 获取年第几周;
 */
const getYearWeek = (year: number, month: string, day: number | undefined) => {
  let date1 = new Date(year, parseInt(month) - 1, day),
    date2 = new Date(year, 0, 1),
    d = Math.round((date1.valueOf() - date2.valueOf()) / 86400000);
  return Math.ceil((d + (date2.getDay() + 1 - 1)) / 7);
};

getMonthscalendar(Number(year));

watch(
  () => propsData.year,
  (newVal) => {
    allMonthObj.allMonthList = [];
    getMonthscalendar(Number(newVal));
  },
);
</script>

组件样式

src/components/Calender/style/index.scss:

.calender_wrapper {
  width: 100%;
  overflow: hidden;
  .month_box_wrapper {
    margin-top: 20px;
    margin-left: 25px;
    height: calc(100vh - 145px);
    overflow-y: scroll;
    .month_box {
      margin-left: 10px;
      margin-right: 10px;
      margin-bottom: 20px;
      float: left;
      .month_tit {
        margin-top: 10px;
        margin-bottom: 10px;
        text-align: center;
      }
      .tb {
        margin: auto;
        border-collapse: collapse;
        .tr {
          td {
            padding: 15px;
            border: 1px solid #aaaaaa63;
            &.week_num {
              color: #fff !important;
              background-color: #ff6702;
            }
          }
          &:not(.tit) {
            td {
              color: #b7b7b7;
              &.current_month {
                color: #000;
              }
              &.today {
                padding: 0px;
                text-align: center;
                .today_text {
                  display: inline-block;
                  width: 25px;
                  height: 25px;
                  line-height: 25px;
                  border-radius: 50%;
                  text-align: center;
                  color: #fff;
                  background: #ff6702;
                }
              }
            }
          }
        }
      }
    }
  }
}

完整的代码

src/components/Calender/index.vue:

<template>
  <div class="calender_wrapper">
    <el-scrollbar>
      <div class="month_box_wrapper">
        <div class="month_box" v-for="item in allMonthObj.allMonthList">
          <h3 class="month_tit">{{ item.month }}月</h3>
          <table class="tb">
            <!--星期几;-->
            <tr class="tr tit">
              <td></td>
              <td></td>
              <td></td>
              <td></td>
              <td></td>
              <td></td>
              <td style="color: #e51f1f"></td>
              <td style="color: #e51f1f"></td>
            </tr>
            <!--日期展示;-->
            <tr class="tr" v-for="itemTr in item.dayList">
              <td class="week_num">{{ itemTr.week }}</td>
              <td v-for="itemTd in itemTr.weekData" :class="{ current_month: itemTd.currentMonth, today: itemTd.today }">
                <template v-if="itemTd.today">
                  <span class="today_text">{{ itemTd.date }}</span>
                </template>
                <template v-else>{{ itemTd.date }}</template>
              </td>
            </tr>
          </table>
        </div>
      </div>
    </el-scrollbar>
  </div>
</template>

<script lang="ts" setup>
import { reactive, watch } from 'vue';

interface props {
  year: number | string;
  monthList: number[];
}
let propsData = defineProps<props>();
const { year, monthList } = propsData;

let allMonthObj: any = reactive({
  allMonthList: [],
});

/**
 * 生成日历;
 */
const getcalendar = (year: number, month: number) => {
  let allDayList: any[] = [];
  year = year ? year : new Date().getFullYear();
  //month是0开始到11结束的,获取当前月份必须加1
  month = month ? month : new Date().getMonth() + 1;
  let last = new Date(year, month - 1, 0);
  let lastdate = last.getDate(); //获取上个月的最大日期
  let lastday = last.getDay(); //获取上个月最大日期的星期几
  let months = new Date(year, month, 0);
  let Maxdate = months.getDate(); //获取这个月最大的日期
  let today = new Date().getDate();
  let thisyear = new Date().getFullYear();
  let thismonth = new Date().getMonth() + 1;
  //获取上个月在这个月份中存在的最后日期
  var remainlastdate = lastdate - lastday + 1;
  var t = 1;
  var week = 1;
  // 首行数据解析;
  allDayList.push({ week: null, weekData: [] });
  for (var g = 1; g <= 7; g++) {
    if (g <= lastday) {
      allDayList[0].weekData.push({ date: remainlastdate++, currentMonth: false });
    } else {
      if (thisyear == year && thismonth == month && today == t) {
        allDayList[0].weekData.push({ date: t++, today: true });
      } else {
        allDayList[0].weekData.push({ date: t++, currentMonth: true });
      }
      allDayList[0].week = getYearWeek(year, month.toString(), t - 1);
    }
  }
  var remainlastday = 7 - lastday + 1;
  var nextMonthday = 1; //下一个月份的开始日期
  for (var i = 1; i <= 5; i++) {
    allDayList.push({ week: null, weekData: [] });
    for (var j = 0; j < 7; j++) {
      if (remainlastday <= Maxdate) {
        if (thisyear == year && thismonth == month && today == remainlastday) {
          allDayList[i].weekData.push({ date: remainlastday++, today: true });
          allDayList[i].week = getYearWeek(year, month.toString(), remainlastday - 1);
        } else {
          allDayList[i].weekData.push({ date: remainlastday++, currentMonth: true });
          allDayList[i].week = getYearWeek(year, month.toString(), remainlastday - 1);
        }
      } else {
        allDayList[i].weekData.push({ date: nextMonthday++, currentMonth: false });
        month < 12 && (allDayList[i].week = getYearWeek(year, (month + 1).toString(), nextMonthday - 1));
      }
    }
  }
  return allDayList;
};
/**
 * 生成每个月的日历;
 */
const getMonthscalendar = (year: number) => {
  monthList.map((item) => {
    allMonthObj.allMonthList.push({ month: item, dayList: getcalendar(year, item) });
  });
};

/**
 * 获取年第几周;
 */
const getYearWeek = (year: number, month: string, day: number | undefined) => {
  let date1 = new Date(year, parseInt(month) - 1, day),
    date2 = new Date(year, 0, 1),
    d = Math.round((date1.valueOf() - date2.valueOf()) / 86400000);
  return Math.ceil((d + (date2.getDay() + 1 - 1)) / 7);
};

getMonthscalendar(Number(year));

watch(
  () => propsData.year,
  (newVal) => {
    allMonthObj.allMonthList = [];
    getMonthscalendar(Number(newVal));
  },
);
</script>
<style lang="scss" scoped>
@import './style/index.scss';
</style>

组件使用

<Calender :year="2023" :monthList="[1,2,3,4,5,6,7,8,9,10,11,12]"></Calender>

组件渲染效果

1677048214036.png

拓展

日历显示
获取当前时间(年月日)是本月第几周和年的第几周的方法